给你一个整数数组 nums 和一个整数 k 。区间 [left, right](left <= right)的 异或结果 是对下标位于 left 和 right(包括 left 和 right )之间所有元素进行 XOR 运算的结果:nums[left] XOR nums[left+1] XOR … XOR nums[right] 。
返回数组中 要更改的最小元素数 ,以使所有长度为 k 的区间异或结果等于零。
示例 1:
输入:nums = [1,2,0,3,0], k = 1
输出:3
解释:将数组 [1,2,0,3,0] 修改为 [0,0,0,0,0]
示例 2:
输入:nums = [3,4,5,2,1,7,3,4,7], k = 3
输出:3
解释:将数组 [3,4,5,2,1,7,3,4,7] 修改为 [3,4,7,3,4,7,3,4,7]
示例 3:
输入:nums = [1,2,4,1,2,5,1,2,6], k = 3
输出:3
解释:将数组[1,2,4,1,2,5,1,2,6] 修改为 [1,2,3,1,2,3,1,2,3]
提示:
1 <= k <= nums.length <= 2000
0 <= nums[i] <
2
10
2^{10}
210
链接:https://leetcode-cn.com/problems/make-the-xor-of-all-segments-equal-to-zero
思路:动态规划
本题难度较大:
为了使所有长度为 k 的区间异或结果等于零,数组nums 在修改之后是一个以 k 为周期的周期性数组, 即对
∀
i
∈
[
0
,
n
−
k
)
,
n
u
m
s
[
i
]
=
=
n
u
m
s
[
i
+
k
]
\forall i\in [0,n-k),nums[i]==nums[i+k]
∀i∈[0,n−k),nums[i]==nums[i+k].
这里为了便于复习,记录一下,详细解题思路参见官方题解。
下面是题解之一:
class Solution {
public:
static constexpr int N = 1024; // 2^10
int minChanges(vector<int>& nums, int k) {
int n = nums.size();
vector<int> group_amount(k);
vector<unordered_map<int, int>> group_record(k);
for(int i = 0; i < n; i++) {
group_amount[i%k]++;//第k列的元素个数
group_record[i%k][nums[i]]++;//num[i]在第i%k列出现的次数
}
vector<vector<int>> dp(k, vector<int>(N));
for(int j = 0; j < N; j++)
dp[0][j] = group_amount[0] - group_record[0][j];
for(int i = 1; i < k; i++) {//共k列
int upper_limit = *min_element(dp[i-1].begin(), dp[i-1].end()) + group_amount[i];
//上界:第k列所有元素都要更改
fill(dp[i].begin(), dp[i].end(), upper_limit);
for(auto [num, amount] : group_record[i])//遍历第k列的元素
for(int j = 0; j < N; j++)
dp[i][j^num] = min(dp[i][j^num], dp[i-1][j] + group_amount[i] - amount);
}
return dp[k-1][0];
}
};