返回
C/C++ 2317. 操作后的最大异或和:充分利用数学原理,轻松高效解决!
后端
2023-12-26 02:17:20
题目
给定一个由非负整数组成的数组 nums
和一个正整数 k
,您需要执行以下操作任意次:
- 选择一个整数
i
,其中0 <= i < nums.length
,并令nums[i] = nums[i] xor k
。 - 移除数组
nums
中的所有零元素。
您的目标是让剩余的数组元素的最大异或和尽可能大。
请返回您能得到的最大的异或和。
注意:
1 <= nums.length <= 500
0 <= nums[i], k <= 10^5
题目整理
- 输入 :非负整数数组
nums
和正整数k
。 - 输出 :剩余数组元素的最大异或和。
- 约束条件 :
1 <= nums.length <= 500
0 <= nums[i], k <= 10^5
解题思路
异或和的性质
为了解决该问题,我们需要了解异或和的一些性质:
- 异或和的结合律和交换律:对于任意整数
a
、b
和c
,有(a xor b) xor c = a xor (b xor c)
和a xor b = b xor a
。 - 异或和的幂等律:对于任意整数
a
,有a xor a = 0
。 - 异或和的逆元:对于任意非零整数
a
,存在唯一的整数b
,使得a xor b = 0
,我们称b
为a
的异或和的逆元。
贪心算法
基于异或和的性质,我们可以使用贪心算法来解决该问题:
- 将
nums
数组中的所有元素按从大到小的顺序排序。 - 对于数组中的每个元素
nums[i]
:- 如果
nums[i]
的异或和逆元b
存在于数组中,则将nums[i]
和b
从数组中移除。 - 否则,将
nums[i]
与k
进行异或运算,得到nums[i] xor k
,并将其添加到数组中。
- 如果
重复步骤 2,直到数组中只剩下一个元素或数组为空。此时,数组中剩下的元素就是能得到的最大异或和。
动态规划
我们也可以使用动态规划来解决该问题:
- 定义状态
dp[i][j]
为在考虑数组nums
的前i
个元素时,最大异或和为j
的方案数。 - 初始化
dp[0][0] = 1
,其他dp[i][j] = 0
。 - 对于数组中的每个元素
nums[i]
:- 对于每个可能的异或和
j
:- 如果
nums[i]
的异或和逆元b
存在于数组中,并且j xor b
也存在于数组中,则dp[i][j] += dp[i - 1][j xor b]
。 - 否则,
dp[i][j xor nums[i]] += dp[i - 1][j]
。
- 如果
- 对于每个可能的异或和
最终,dp[nums.length][k]
的值就是能得到的最大异或和的方案数。
实现和代码
C++ 实现
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
int maxResult(vector<int>& nums, int k) {
sort(nums.begin(), nums.end(), greater<int>());
int n = nums.size();
vector<int> dp(100001, 0);
dp[0] = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j <= 100000; j++) {
if (dp[j]) {
int b = j ^ nums[i];
if (b >= 0 && b <= 100000) {
dp[j ^ nums[i]] += dp[j];
}
dp[j xor k] += dp[j];
}
}
}
int maxXor = 0;
for (int i = 0; i <= 100000; i++) {
if (dp[i] > 0) {
maxXor = max(maxXor, i);
}
}
return maxXor;
}
};
Java 实现
import java.util.Arrays;
class Solution {
public int maxResult(int[] nums, int k) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
for (int i = 1; i < n; i++) {
for (int j = i - 1; j >= 0 && j >= i - k; j--) {
dp[i] = Math.max(dp[i], dp[j] ^ nums[i]);
}
}
return dp[n - 1];
}
}
复杂度分析
- 时间复杂度 :
- 贪心算法的时间复杂度为
O(n log n)
,其中n
是数组nums
的长度。 - 动态规划的时间复杂度为
O(n * k)
,其中n
是数组nums
的长度,k
是正整数k
的值。
- 贪心算法的时间复杂度为
- 空间复杂度 :
- 贪心算法的空间复杂度为
O(n)
,其中n
是数组nums
的长度。 - 动态规划的空间复杂度为
O(n * k)
,其中n
是数组nums
的长度,k
是正整数k
的值。
- 贪心算法的空间复杂度为