• 力扣1787


    题目

    给你一个整数数组 nums​​​ 和一个整数 k​​​​​ 。区间 [left, right](left <= right)的 异或结果 是对下标位于 left 和 right(包括 left 和 right )之间所有元素进行 XOR 运算的结果:nums[left] XOR nums[left+1] XOR ... XOR nums[right] 。

    返回数组中 要更改的最小元素数 ,以使所有长度为 k 的区间异或结果等于零。

    题解

    A1^A2^...^Ak=0
    A2^A3^....^Ak+1=0
    ..
    根据上式可得
    A1=Ak+1
    A2=Ak+2
    A3=Ak+3
    ...
    只关注前k个数字异或和为0
    因此题目变成求解前k个数字异或和为0,其余数字变成前k个数字后尽可能修改的小
    [1,2,3, 1,2,5, 1,2,6]
    a=1: 代价为3-3=0 (all-cur) cur是要改成某个数字,在当前index下有多次出现
    a=2: 代价为3-0=3
    前k个数字等于什么的代价不同,代价需要预先计算
    dp[i][v]表示前i个数字异或和为v的最小代价是多少
    dp[i-1][v] +cost(s) --> dp[i][v^s]
    如果单纯暴力枚举v和s,总的时间复杂度为O(102410242000)
    而实际计算过程中,每个index%k的位置上实际上由很多重复的数字,对于未出现的数字,可以一次计算

    const int MAXN=2010;
    const int MAXV=1024;
    int all[MAXN];
    unordered_map<int,int>cur[MAXN];
    int dp[MAXN][MAXV];
    //O(K*V+N*V) 只关注前k个,dp[i][s]表示前i个词,异或和为s时的最小交换次数
    class Solution {
    public:
        int minChanges(vector<int>& nums, int k) {
            int n=nums.size();
            for(int i=0;i<n;i++) cur[i].clear();
            memset(all,0,sizeof(all));
            for(int i=0;i<n;i++){
                all[i%k]++; //第i%k的个数
                cur[i%k][nums[i]]++; //第i%k个下标数字nums[i]出现的次数
            }
            memset(dp,-1,sizeof(dp));
            dp[0][0]=0;
            for(int i=1;i<=k;i++){
                int mi=2010;
                for(int s=0;s<MAXV;s++){ //预先处理出一个上界
                    if(dp[i-1][s]==-1) continue;
                    if(mi>dp[i-1][s]) mi=dp[i-1][s]; 
                }
                mi+=all[i-1]; //未出现在第i个位置的数字(上界)
                for(int s=0;s<MAXV;s++){
                    if(dp[i][s]==-1||dp[i][s]>mi) dp[i][s]=mi;
                    if(dp[i-1][s]==-1) continue;
                    for(auto it=cur[i-1].begin();it!=cur[i-1].end();it++){ //在位置i出现的所有数字
                        int v=it->first,c=it->second;
                        int cost=dp[i-1][s]+all[i-1]-c;
                        if(dp[i][s^v]==-1||dp[i][s^v]>cost) dp[i][s^v]=cost;
                    }
                }
            }
            return dp[k][0];
        }
    };
    
  • 相关阅读:
    网页轮播图案例
    表单
    表格标签的使用
    HTML5标签2
    HTML标签
    外边距
    h5css产品模块设计
    mouseenter 和mouseover的区别
    动画函数封装
    jQuery 插件
  • 原文地址:https://www.cnblogs.com/flightless/p/14810592.html
Copyright © 2020-2023  润新知