千问 LeetCode 1879.两个数组最小的异或值之和 public int minimumXORSum(int[] nums1, int[] nums2)
只能选 j=1:nums2[1]=3,newMask=3,xor=2^3=1,dp[3]=min(∞, 3+1)=4。- 只能选 j=0:nums2[0]=2,newMask=3,xor=2^2=0,dp[3]=min(4, 2+0)=2。- 尝试 j=0:nums2[0]=2,newMask=1,xor=1^2=3,dp[1]=min(∞, 0+3)=3。- 尝试 j=1:nums2[1]=3,
这是一道经典的状态压缩动态规划问题。
题目要求将 nums1 中的每个元素与 nums2 中的每个元素进行一一配对,使得所有配对的异或值之和最小。
由于数组长度最多为 14,我们可以用二进制位来表示 nums2 中哪些元素已经被使用过,这就是状态压缩的核心思想。
🧠 核心思路
1. 状态定义
设 dp[mask] 表示 nums2 中使用情况为 mask 时,已经配对的元素所产生的最小异或和。
- mask 是一个二进制数,第 j 位为 1 表示 nums2[j] 已经被使用。
- 例如 mask = 5 (二进制 101) 表示 nums2[0] 和 nums2[2] 已被使用。
2. 状态转移
对于状态 mask,我们已经使用了 k 个 nums2 的元素,这意味着 nums1 的前 k 个元素也已经配对完成。
现在我们要为 nums1[k] 选择一个未使用的 nums2[j] 进行配对。
- k = popcount(mask) (mask 中 1 的个数)
- 对于每个未使用的 j(即 mask 的第 j 位为 0):
- 新的状态:new_mask = mask | (1 = n) continue;
// 尝试为 nums1[usedCount] 选择一个未使用的 nums2[j]
for (int j = 0; j < n; j++) {
// 检查 nums2[j] 是否未被使用
if ((mask & (1 << j)) == 0) {
int newMask = mask | (1 << j);
int xorValue = nums1[usedCount] ^ nums2[j];
dp[newMask] = Math.min(dp[newMask], dp[mask] + xorValue);
}
}
}
// 返回所有元素都配对完成的最小异或和
return dp[totalStates - 1];
}
}
🧮 示例解析
假设 nums1 = [1,2], nums2 = [2,3]
1. 初始状态:dp[0] = 0
2. mask = 0(未使用任何元素):
- usedCount = 0,要为 nums1[0]=1 配对
- 尝试 j=0:nums2[0]=2,newMask=1,xor=1^2=3,dp[1]=min(∞, 0+3)=3
- 尝试 j=1:nums2[1]=3,newMask=2,xor=1^3=2,dp[2]=min(∞, 0+2)=2
3. mask = 1(nums2[0] 已用):
- usedCount = 1,要为 nums1[1]=2 配对
- 只能选 j=1:nums2[1]=3,newMask=3,xor=2^3=1,dp[3]=min(∞, 3+1)=4
4. mask = 2(nums2[1] 已用):
- usedCount = 1,要为 nums1[1]=2 配对
- 只能选 j=0:nums2[0]=2,newMask=3,xor=2^2=0,dp[3]=min(4, 2+0)=2
5. 结果:dp[3] = 2
⏱️ 复杂度分析
- 时间复杂度:O(n times 2^n)
- 有 2^n 个状态
- 每个状态最多尝试 n 次转移
- 空间复杂度:O(2^n)
- 用于存储 dp 数组
💡 优化提示
由于 n <= 14,2^{14} = 16384,这个解法在时间和空间上都是可行的。状态压缩动态规划是解决这类配对问题的标准方法。
更多推荐




所有评论(0)