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];
    }
};

 


和这个题差不多待学习
posted @ 2021-05-30 23:47  lipu123  阅读(127)  评论(0)    收藏  举报