力扣 1787. 使所有区间的异或结果为零 dp 位运算

129 篇文章 2 订阅
6 篇文章 0 订阅

https://leetcode-cn.com/problems/make-the-xor-of-all-segments-equal-to-zero/
在这里插入图片描述
思路:依据题意,有:
n u m s [ i ]   x o r   n u m s [ i + 1 ] … … x o r   n u m s [ i + k − 1 ] = 0     ( 1 ) n u m s [ i + 1 ]   x o r   n u m s [ i + 2 ] … … x o r   n u m s [ i + k ] = 0     ( 2 ) nums[i]\ xor\ nums[i+1]……xor\ nums[i+k-1]=0 \ \ \ (1)\\ nums[i+1]\ xor\ nums[i+2]……xor\ nums[i+k]=0\ \ \ (2) nums[i] xor nums[i+1]xor nums[i+k1]=0   (1)nums[i+1] xor nums[i+2]xor nums[i+k]=0   (2)
( 1 ) 、 ( 2 ) (1)、(2) (1)(2)异或可得: n u m s [ i ]   x o r   n u m s [ i + k ] = 0 nums[i]\ xor\ nums[i+k]=0 nums[i] xor nums[i+k]=0,即 n u m s [ i ] = n u m s [ i + k ] nums[i]=nums[i+k] nums[i]=nums[i+k],因此最后符合题意的数组一定是有循环节的,循环长度为 k k k。因此我们可以把数组分为 k k k组,考虑用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示处理到第 i i i组且 [ 0 , i ] [0,i] [0,i]组所有元素异或和( n u m s [ 0 ]   x o r … … n u m s [ i ] nums[0]\ xor……nums[i] nums[0] xornums[i])为 j j j的情况下所需要更改的最小元素数。

对于第 i i i组元素,假设把它们全部变化为 x x x,那么有:
d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j   x o r   x ] + s i z e ( i ) − c o u n t ( x ) ) dp[i][j]=min(dp[i-1][j\ xor\ x]+size(i)-count(x)) dp[i][j]=min(dp[i1][j xor x]+size(i)count(x))
其中 s i z e ( i ) size(i) size(i)为第 i i i组元素的个数, c o u n t ( x ) count(x) count(x)为元素 x x x在该组内出现的次数。考虑到 n u m s [ i ] < 2 10 nums[i]<2^{10} nums[i]<210,因此上述算法的复杂度为 O ( k ∗ 2 10 ∗ 2 10 ) O(k*2^{10}*2^{10}) O(k210210),会超时。

接下来考虑优化,首先 s i z e ( i ) size(i) size(i) x x x无关,可以提出去;然后考虑当 c o u n t ( x ) = 0 count(x)=0 count(x)=0时,上述公式可以转换为:
d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j   x o r   x ] ) + s i z e ( i )     ( 3 ) dp[i][j]=min(dp[i-1][j\ xor\ x])+size(i)\ \ \ (3) dp[i][j]=min(dp[i1][j xor x])+size(i)   (3)
对于确定的 i 、 j i、j ij,这个可以在 O ( 2 10 ) O(2^{10}) O(210)内计算出来。

c o u n t ( x ) ≠ 0 count(x)\not= 0 count(x)=0时,我们依然需要枚举 x x x,但是可以只枚举出现过的 x x x,这时公式依然为:
d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j   x o r   x ] − c o u n t ( x ) ) + s i z e ( i )     ( 4 ) dp[i][j]=min(dp[i-1][j\ xor\ x]-count(x))+size(i)\ \ \ (4) dp[i][j]=min(dp[i1][j xor x]count(x))+size(i)   (4)
但是我们可以发现当 c o u n t ( x ) ≠ 0 count(x)\not= 0 count(x)=0时, ( 4 ) (4) (4)一定要小于 ( 3 ) (3) (3),由于我们取的是最小值,因此把 ( 4 ) (4) (4)一起考虑也没有关系。所以不管 x x x是否在该组出现过,我们都可以先令 d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j   x o r   x ] ) + s i z e ( i ) dp[i][j]=min(dp[i-1][j\ xor\ x])+size(i) dp[i][j]=min(dp[i1][j xor x])+size(i),然后再枚举出现过的 x x x ( 4 ) (4) (4)更新。这样复杂度可以降低到 O ( ( k + n ) ∗ 2 10 ) O((k+n)*2^{10}) O((k+n)210)

class Solution {
public:
    int minChanges(vector<int>& nums, int k) {
        const int maxn=1<<10;
        const int inf=0x3f3f3f3f;
        int n=nums.size();
        vector<int> dp(maxn,inf);
        dp[0]=0;
        for(int i=0;i<k;i++)
        {
            int size=0;
            unordered_map<int,int> cnt;
            for(int j=i;j<n;j+=k)
            {
                ++cnt[nums[j]];
                ++size;
            }
            int min_value=*min_element(dp.begin(),dp.end());
            vector<int> dp2(maxn,min_value);
            for(int j=0;j<maxn;j++)
            {
                for(const auto &pr:cnt)
                    dp2[j]=min(dp2[j],dp[j^pr.first]-pr.second);
                dp2[j]+=size;
            }
            dp=move(dp2);
        }
        return dp[0];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值