5756. 两个数组最小的异或值之和(状态压缩dp)
给你两个整数数组 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.length
n == nums2.length
1 <= n <= 14
0 <= nums1[i], nums2[i] <= 107
这个题是一个经典的n!的复杂度的一个题转化成一个2^n*n的状态压缩dp,这个题为什么可以转换呢,就是比如说前i个,它不考虑它的顺序了,只考虑那个
放在最后一个,这样可以降低复杂度,
/*
暴力:枚举b数组全排列进行异或!
思路:我们可以从前往后摆所有元素,由于后面要摆的元素和前面已摆的元素顺序无关,只与是否使用过有关!
因此:我们可以使用二进制状态来表示这个状态!
状压DP:
状态表示:f[i]表示状态为i的摆法的集合!属性:异或值和最小!
状态计算:按照最后一个摆的元素划分!
f[i] = min(f[i], f[i - (1 << j)] + (b[j] ^ a[s - 1]));
解释:若最后一个摆放元素下标为j,则之前状态为i - (1 << j)
s为已经摆放元素的个数!(也就是二进制状态中1的个数)
此时异或的两个数为 b[j] 和 a[s - 1](下标从0开始,要-1)
初始化:f[0] = 0,其他为INT_MAX
最终答案:f[(1 << n) - 1](即n个数全摆放完毕的最小异或值)
*/
class Solution { public: int minimumXORSum(vector<int>& nums1, vector<int>& nums2) { int n=nums1.size(),INF=1e9; vector<int> f(1<<n,INF); f[0]=0; for(int i=1;i<(1<<n);i++){ int s=0; for(int j=0;j<n;j++){ if((i>>j)&1){ s++; } } for(int j=0;j<n;j++){ if((i>>j)&1){ f[i] = min(f[i], f[i - (1 << j)] + (nums2[j] ^ nums1[s - 1])); } } } return f[(1<<n)-1]; } };
和这个题差不多待学习