【C/C++】2317. 操作后的最大异或和

511 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情


题目链接:2317. 操作后的最大异或和

题目描述

给你一个下标从 0 开始的整数数组 nums 。一次操作中,选择 任意 非负整数 x 和一个下标 i ,更新 nums[i] 为 nums[i] AND (nums[i] XOR x) 。

注意,AND 是逐位与运算,XOR 是逐位异或运算。

请你执行 任意次 更新操作,并返回 nums 中所有元素 最大 逐位异或和。

提示:

  • 1nums.length1051 \leqslant nums.length \leqslant 10^5
  • 0nums[i]1080 \leqslant nums[i] \leqslant 10^8

示例 1:

输入:nums = [3,2,4,6]
输出:7
解释:选择 x = 4 和 i = 3 进行操作,num[3] = 6 AND (6 XOR 4) = 6 AND 2 = 2 。
现在,nums = [3, 2, 4, 2] 且所有元素逐位异或得到 3 XOR 2 XOR 4 XOR 2 = 7 。
可知 7 是能得到的最大逐位异或和。
注意,其他操作可能也能得到逐位异或和 7 。

示例 2:

输入:nums = [1,2,3,9,2]
输出:11
解释:执行 0 次操作。
所有元素的逐位异或和为 1 XOR 2 XOR 3 XOR 9 XOR 2 = 11 。
可知 11 是能得到的最大逐位异或和。

整理题意

题目给定数组 nums,为了使得数组最后所有整数异或的值最大,我们可以对数组中的元素进行 任意次 更新操作,将 nums[i] 更新为 nums[i] AND (nums[i] XOR x)

最后返回更新后的数组中所有整数异或的最大值。

解题思路分析

首先要明白两个运算规则:

  • 异或:相同为零,相异为一。
  • 与:只有都为一的时候才为一,其他情况为零。

再来观察这个更新操作:nums[i] = nums[i] AND (nums[i] XOR x)

  • 先不看小括号里的运算,最后运算为 nums[i] 和括号运算结果进行与操作,那么可能得到的最大值也就为 nums[i],也就是最多只能保留 nums[i] 二进制下已有的 1
  • 再来看括号里的运算,我们可以取任意 x 来改变 nums[i] 为任意数,换句话说也就是括号里的数可以由我们决定,改变为我们想要的任意数。 综上,我们可以得到结论:我们的更新操作可以将 nums[i] 二进制下某些位上的 1 改变为 0,但无法将某些位上的 0 改变为 1

由异或运算规则相异为一可知,对于二进制下某一位来说,如果数组所有整数在该位上 1 的个数为奇数个,那么最后该位异或值就为 1,那么为了构造出使得最后异或值最大,我们希望数组中所有数在二进制下每一位的和都为奇数个。如果二进制下某一位的和为偶数个 1 时(非 0 偶数),我们可以采取更新操作使得该位 1 的个数减少一个变为奇数个。

具体实现

  1. 按照解题思路模拟,我们依次统计数组中二进制下每一位上 1 的个数。
  2. 最后将二进制下每一位 1 的个数统计不为 0 的值进行累加答案。

优化

根据具体实现中的第 2 步我们可以得知,对于二进制下每一位来说,只要数组中有一个整数在该位上有 1 即可,那么我们直接将数组中的所有整数 按位或 即可得到答案。

按位或运算规则:只有全为零时才为零,其他情况为一。

复杂度分析

  • 时间复杂度:O(n)O(n)n 为数组长度,仅需遍历一遍数组。
  • 空间复杂度:O(1)O(1),仅需常数空间。

代码实现

class Solution {
public:
    int maximumXOR(vector<int>& nums) {
        int ans = 0;
        for(int x : nums) ans |= x;
        return ans;
    }
};

总结

  • 该题为脑筋急转弯题目,可以用 贪心 的思想进行解题。
  • 因为更新操作最后需要与 nums[i] 进行 操作,所以只能将 nums[i] 二进制下部分 1 置为 0,而不能将 0 置为 1,因此问题转化为求将 nums[i] 中二进制位任意 1 转化为 0 后的最大异或值。
  • 那么可得最优解为二进制下相同位只用保留 11 即可,将其余相同位置为 0,有 1 即可,可以想到或运算,那么最终最优解就为数组中所有整数按位或即为答案。
  • 测试结果:

2317.png

结束语

我们偶尔会发现自己的脚步停滞不前,与目标只差一点点距离,其实,那一点距离的名字叫坚持。无论今天要面对什么,既然走到这一步,就坚持下去,给自己一些肯定,相信多努力一点,我们就能抵达想去的远方。新的一天,加油!