描述:给定两个整数数组 nums1 和 nums2,两个数组长度都为 n。
要求:将 nums2 中的元素重新排列,使得两个数组的异或值之和最小。并返回重新排列之后的异或值之和。
说明:
- 两个数组的异或值之和:(nums1[0]⊕nums2[0])+(nums1[1]⊕nums2[1])+...+(nums1[n−1]⊕nums2[n−1])(下标从 0 开始)。
- 举个例子,[1,2,3] 和 [3,2,1] 的异或值之和 等于 (1⊕3)+(2⊕2)+(3⊕1)+(3⊕1)=2+0+2=4。
- n==nums1.length。
- n==nums2.length。
- 1≤n≤14。
- 0≤nums1[i],nums2[i]≤107。
示例:
输入:nums1 = [1,2], nums2 = [2,3]
输出:2
解释:将 nums2 重新排列得到 [3,2] 。
异或值之和为 (1 XOR 3) + (2 XOR 2) = 2 + 0 = 2。
输入:nums1 = [1,0,3], nums2 = [5,3,4]
输出:8
解释:将 nums2 重新排列得到 [5,4,3] 。
异或值之和为 (1 XOR 5) + (0 XOR 4) + (3 XOR 3) = 4 + 4 + 0 = 8。
由于数组 nums2 可以重新排列,所以我们可以将数组 nums1 中的元素顺序固定,然后将数组 nums1 中第 i 个元素与数组 nums2 中所有还没被选择的元素进行组合,找到异或值之和最小的组合。
同时因为两个数组长度 n 的大小范围只有 [1,14],所以我们可以采用「状态压缩」的方式来表示 nums2 中当前元素的选择情况。
「状态压缩」指的是使用一个 n 位的二进制数 state 来表示排列中数的选取情况。
如果二进制数 state 的第 i 位为 1,说明数组 nums2 第 i 个元素在该状态中被选取。反之,如果该二进制的第 i 位为 0,说明数组 nums2 中第 i 个元素在该状态中没有被选取。
举个例子:
- nums2={1,2,3,4},state=(1001)2,表示选择了第 1 个元素和第 4 个元素,也就是 1、4。
- nums2={1,2,3,4,5,6},state=(011010)2,表示选择了第 2 个元素、第 4 个元素、第 5 个元素,也就是 2、4、5。
这样,我们就可以通过动态规划的方式来解决这道题。
按照数组 nums 中元素选择情况进行阶段划分。
定义当前数组 nums2 中元素选择状态为 state,state 对应选择的元素个数为 count(state)。
则可以定义状态 dp[state] 表示为:当前数组 nums2 中元素选择状态为 state,并且选择了 nums1 中前 count(state) 个元素的情况下,可以组成的最小异或值之和。
对于当前状态 dp[state],肯定是从比 state 少选一个元素的状态中递推而来。我们可以枚举少选一个元素的状态,找到可以组成的异或值之和最小值,赋值给 dp[state]。
举个例子 nums2={1,2,3,4},state=(1001)2,表示选择了第 1 个元素和第 4 个元素,也就是 1、4。那么 state 只能从 (1000)2 和 (0001)2 这两个状态转移而来,我们只需要枚举这两种状态,并求出转移过来的异或值之和最小值。
即状态转移方程为:dp[state]=min(dp[state],dp[state⊕(1 << i)]+(nums1[i]⊕nums2[onecnt−1])),其中 state 第 i 位一定为 1,onecnt 为 state 中 1 的个数。
- 既然是求最小值,不妨将所有状态初始为最大值。
- 未选择任何数时,异或值之和为 0,所以初始化 dp[0]=0。
根据我们之前定义的状态,dp[state] 表示为:当前数组 nums2 中元素选择状态为 state,并且选择了 nums1 中前 count(state) 个元素的情况下,可以组成的最小异或值之和。 所以最终结果为 dp[states−1],其中 states=1 << n。
class Solution:
def minimumXORSum(self, nums1: List[int], nums2: List[int]) -> int:
ans = float('inf')
size = len(nums1)
states = 1 << size
dp = [float('inf') for _ in range(states)]
dp[0] = 0
for state in range(states):
one_cnt = bin(state).count('1')
for i in range(size):
if (state >> i) & 1:
dp[state] = min(dp[state], dp[state ^ (1 << i)] + (nums1[i] ^ nums2[one_cnt - 1]))
return dp[states - 1]
- 时间复杂度:O(2n×n),其中 n 是数组 nums1、nums2 的长度。
- 空间复杂度:O(2n)。