leetcode
leetcode 2551 ~ 2600
给定操作次数内使剩余元素的或值最小

给定操作次数内使剩余元素的或值最小

难度:

标签:

题目描述

You are given a 0-indexed integer array nums and an integer k.

In one operation, you can pick any index i of nums such that 0 <= i < nums.length - 1 and replace nums[i] and nums[i + 1] with a single occurrence of nums[i] & nums[i + 1], where & represents the bitwise AND operator.

Return the minimum possible value of the bitwise OR of the remaining elements of nums after applying at most k operations.

 

Example 1:

Input: nums = [3,5,3,2,7], k = 2
Output: 3
Explanation: Let's do the following operations:
1. Replace nums[0] and nums[1] with (nums[0] & nums[1]) so that nums becomes equal to [1,3,2,7].
2. Replace nums[2] and nums[3] with (nums[2] & nums[3]) so that nums becomes equal to [1,3,2].
The bitwise-or of the final array is 3.
It can be shown that 3 is the minimum possible value of the bitwise OR of the remaining elements of nums after applying at most k operations.

Example 2:

Input: nums = [7,3,15,14,2,8], k = 4
Output: 2
Explanation: Let's do the following operations:
1. Replace nums[0] and nums[1] with (nums[0] & nums[1]) so that nums becomes equal to [3,15,14,2,8]. 
2. Replace nums[0] and nums[1] with (nums[0] & nums[1]) so that nums becomes equal to [3,14,2,8].
3. Replace nums[0] and nums[1] with (nums[0] & nums[1]) so that nums becomes equal to [2,2,8].
4. Replace nums[1] and nums[2] with (nums[1] & nums[2]) so that nums becomes equal to [2,0].
The bitwise-or of the final array is 2.
It can be shown that 2 is the minimum possible value of the bitwise OR of the remaining elements of nums after applying at most k operations.

Example 3:

Input: nums = [10,7,10,3,9,14,9,4], k = 1
Output: 15
Explanation: Without applying any operations, the bitwise-or of nums is 15.
It can be shown that 15 is the minimum possible value of the bitwise OR of the remaining elements of nums after applying at most k operations.

 

Constraints:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] < 230
  • 0 <= k < nums.length

代码结果

运行时间: 526 ms, 内存: 28.2 MB


解释

方法:

题解的思路是首先计算数组中所有数字的按位或值 `final` 和按位与值 `finalMust`。`finalMust` 表示所有数字的公共为1的位,这些位无论如何操作都无法改变。接着,尝试从 `final` 中移除某些位来最小化结果。使用一个掩码 `finalMask` 来标识哪些位可以被操作。对于每一位,如果它在 `final` 中但不在 `finalMust` 中,尝试将这一位从1变为0,并检查这样的操作是否可行,即在不超过 k 次操作的情况下,能否通过按位与操作将这一位在所有数字中消除。这个过程从最高位开始,依次向下检查每一位。如果某位可以被消除,则更新 `final` 和 `finalMask`。最终 `final` 将会是经过最多 k 次操作后,所有元素的按位或的最小值。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中,`finalMust` 表示所有数字的公共为1的位,这些位怎样通过操作都无法改变。请问为什么这些位无法通过AND操作改变?
在位运算中,AND操作(按位与)的结果是只有当所有操作数在某一位上都为1时,结果才为1。因此,如果在`finalMust`中某一位是1,意味着数组中所有数字在这一位上都为1。尝试使用AND操作改变这一位时,无论如何与其他数进行AND操作(即使是与0操作),只要数组中的所有数在这一位上原本都为1,结果仍然为1。这就是为什么这些公共为1的位无法通过AND操作改变的原因。
🦆
题解提到使用掩码 `finalMask` 来标识哪些位可以被操作。具体是如何利用这个掩码来判断哪些位可以从1变为0的?
`finalMask` 是通过计算 `(indexIO - 1) ^ final` 得到的,其中 `indexIO` 是大于 `final` 最大位的最小的2的幂。这个掩码的每一位被设置为1,表示相应的位在 `final` 中是0(即可以尝试将其变为0),设置为0则表示该位在 `final` 中为1但不在 `finalMust` 中,即这些位可能通过操作被改变。通过这样的掩码,我们可以快速识别出哪些位是可操作的,从而在算法中对这些位进行特定的处理。
🦆
题解中的循环 `while indexIO := indexIO >> 1` 是如何确保覆盖所有可能的位的?是否有可能遗漏检查某些位?
循环通过将 `indexIO` 不断右移(除以2),从而逐步检查从最高位到最低位的每一个位。循环开始前,`indexIO` 被初始化为大于 `final` 最高位的最小2的幂,确保从最高位开始检查。因此,在循环中,每次迭代都会将 `indexIO` 右移一位,依次检查每一位,直到 `indexIO` 变为0。这样的循环结构确保了每一位都会被检查一次,没有遗漏。
🦆
在计算 `target` 和 `targetMask` 时,为何只通过简单的异或操作 `final ^ indexIO` 和 `finalMask ^ indexIO` 来更新?这种方法有何依据?
异或操作(XOR)具有这样的特性:对于任何位,如果两个操作数的相应位相同则结果为0,不同则为1。在给定的题解算法中,`final ^ indexIO` 的操作用来尝试将 `final` 中的某一位从1改为0(如果该位原来是1)。类似地,`finalMask ^ indexIO` 用于更新掩码,即如果原来这一位在掩码中为0(即在 `final` 中为1),通过异或操作后这一位会变为1,表示这一位已被操作尝试改变。这种方法的依据是异或操作的位反转特性,非常适用于此类位操作场景。

相关问题