leetcode
leetcode 2301 ~ 2350
最大或值

最大或值

难度:

标签:

题目描述

You are given a 0-indexed integer array nums of length n and an integer k. In an operation, you can choose an element and multiply it by 2.

Return the maximum possible value of nums[0] | nums[1] | ... | nums[n - 1] that can be obtained after applying the operation on nums at most k times.

Note that a | b denotes the bitwise or between two integers a and b.

 

Example 1:

Input: nums = [12,9], k = 1
Output: 30
Explanation: If we apply the operation to index 1, our new array nums will be equal to [12,18]. Thus, we return the bitwise or of 12 and 18, which is 30.

Example 2:

Input: nums = [8,1,2], k = 2
Output: 35
Explanation: If we apply the operation twice on index 0, we yield a new array of [32,1,2]. Thus, we return 32|1|2 = 35.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 1 <= k <= 15

代码结果

运行时间: 72 ms, 内存: 28.5 MB


/*
 * Problem: Given an integer array nums and an integer k, you can choose a number and multiply it by 2 in each operation.
 * You can perform at most k operations. Return the maximum value of nums[0] | nums[1] | ... | nums[n - 1].
 * Example:
 * Input: nums = [12, 9], k = 1
 * Output: 30
 * Explanation: By doubling the element at index 1, we get [12, 18]. The result of 12 | 18 is 30.
 */

import java.util.Arrays;

public class Solution {
    public int maximizeOr(int[] nums, int k) {
        return Arrays.stream(nums)
            .map(num -> num << k)
            .reduce(0, (a, b) -> a | b);
    }
}

解释

方法:

该题解主要通过位运算的方法来尝试在进行最多k次数值翻倍的操作后,获取最大的按位或结果。首先,使用两个变量v和v2,其中v存储数组nums中所有元素的按位或结果,v2存储在某些位上至少有两个数都为1的情况的按位或结果。接着,如果v2与v相同,并且v加1后与自身进行按位与的结果为0(说明v是2的幂减一的形式),则直接返回最大数左移k位后与v进行按位或的结果。否则,对于每个数x,计算x左移k位后与其自身与v按位异或后的结果再与v2按位或的结果,并返回这些计算中的最大值。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在解法中,变量`v`和`v2`的目的及其在算法中的作用是什么?
`v`变量用于记录数组`nums`中所有元素的按位或结果。这意味着在数组的所有数字中,只要某一位上至少有一个数是1,那么`v`在该位上也是1。`v2`变量用于记录在`v`已记录位为1的前提下,至少有两个元素在同一位上都为1的情况。这有助于在特定情况下直接计算可能的最大按位或值,特别是当`v`表示一个完整的位模式时(即所有可能的位都被设置为1)。
🦆
解法中提到的条件`v2 == v`和`(v + 1 & v) == 0`分别检查了什么?为什么这些检查后可以直接计算最终结果?
条件`v2 == v`检查是否每个由`v`标记为1的位至少有两个数字在该位上也是1,这意味着通过任何组合的按位或操作,这些1的位不会改变。条件`(v + 1 & v) == 0`是用来检查`v`是否是形如`111...111`(二进制下全1的形式,例如`3`即`11`或`7`即`111`),这表明`v`已经是最大可能的按位或结果。如果这两个条件都满足,意味着无论如何左移或修改最大数,最终的按位或结果都不会超过`v`,因此可以直接使用最大数左移k位后与v按位或得到最终结果。
🦆
如何理解`v2 |= v & x`这一行代码?它是如何更新`v2`的值的?
这行代码`v2 |= v & x`的作用是更新`v2`的值,以包含那些在`v`已经有1的位上,当前元素`x`也为1的位。首先,`v & x`操作产生一个新的数,该数仅在`v`和`x`都为1的位上为1。然后,通过`|=`操作(按位或赋值),将这些位添加到`v2`中。这样,`v2`最终记录了所有至少有两个数字共同为1的位,帮助在特殊情况下直接得到最大按位或值。
🦆
为什么在计算最大按位或值时,会选择将最大数左移k位?这样做的优势在哪里?
将最大数左移k位的优势在于能够增大其数值,从而可能增加最终的按位或结果。左移操作本质上是将数字乘以`2^k`,这会在数的二进制表示的末尾添加k个0。当这个较大的数与其他数进行按位或操作时,由于它提供了更高位的有效位,因此可以最大化按位或的结果。特别是当其他操作无法提供更高位的有效位时,这种方法尤其有用。

相关问题