题目
给你两个整数数组 nums1 和 nums2 ,它们长度都为 n 。
两个数组的 异或值之和 为 (nums1[0] XOR nums2[0]) + (nums1[1] XOR nums2[1]) + … + (nums1[n - 1] XOR nums2[n - 1]) (下标从 0 开始)。
比方说,[1,2,3] 和 [3,2,1] 的 异或值之和 等于 (1 XOR 3) + (2 XOR 2) + (3 XOR 1) = 2 + 0 + 2 = 4 。
请你将 nums2 中的元素重新排列,使得 异或值之和 最小 。
请你返回重新排列之后的 异或值之和 。
示例 1:
输入:nums1 = [1,2], nums2 = [2,3]
输出:2
解释:将 nums2 重新排列得到 [3,2] 。
异或值之和为 (1 XOR 3) + (2 XOR 2) = 2 + 0 = 2 。
示例 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 。
解题思路
假设n是数组的长度,这题可以看成nums1的前c个数字,在nums2中找出c个数字,一一对应,从而使得异或和最小,因此我们可以使用n位的二进制数即可表示nums2的不同取值状态,第j位为1代表该情况下,nums2[j]已经被选择了.
- 例如对于nums1 = [1,2], nums2 = [2,3]
- 01表示nums2[1]=3已经被选择用于与nums1的前一个数字组成异或和了,dp[01]就是代表这种情况的最小异或和
- 10表示nums2[0]=2已经被选择用于与nums1的前一个数字组成异或和了
所以dp[11]应该从dp[01]或者dp[10]转移而来,并且需要加上新产生的异或值
状态转移
找出当前状态的上一步状态,进行转移
- 遍历nums2的每一个元素
(1<<j)&i>0
代表nums2[j]在当前状态下已经被选择,所以我们将这个选择取消(将这一位置零),就是上一步的其中一种状态dp[(1<<j)^i]
for j := 0; j < n; j++ {if (1<<j)&i>0{val:=dp[(1<<j)^i]+(nums1[cnt(i)-1]^nums2[j])if val<dp[i]{dp[i]=val}}}
代码
func minimumXORSum(nums1 []int, nums2 []int) (res int){n:=len(nums1)cnt := func(cur int) (res int) {for k := 0; k < 31; k++ {res+=1&curcur>>=1}return}mask:=1<<ndp := make([]int, mask)for i := 1; i < mask; i++{dp[i]=2e9}for i := 1; i < mask; i++ {for j := 0; j < n; j++ {if (1<<j)&i>0{val:=dp[(1<<j)^i]+(nums1[cnt(i)-1]^nums2[j])if val<dp[i]{dp[i]=val}}}}return dp[mask-1]
}