JAVA程序设计:使所有区间的异或结果为零(LeetCode:1787)

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

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

 

示例 1:

输入:nums = [1,2,0,3,0], k = 1
输出:3
解释:将数组 [1,2,0,3,0] 修改为 [0,0,0,0,0]
示例 2:

输入:nums = [3,4,5,2,1,7,3,4,7], k = 3
输出:3
解释:将数组 [3,4,5,2,1,7,3,4,7] 修改为 [3,4,7,3,4,7,3,4,7]
示例 3:

输入:nums = [1,2,4,1,2,5,1,2,6], k = 3
输出:3
解释:将数组[1,2,4,1,2,5,1,2,6] 修改为 [1,2,3,1,2,3,1,2,3]
 

提示:

1 <= k <= nums.length <= 2000
​​​​​​0 <= nums[i] < 210

思路:仔细想想还是有切入点可循的(比赛时完全没想到,真滴菜),在经过一系列的替换后,可以发现最后a[i]=a[i+k]=a[i+2*k]...的,所以我们应该讲数组分成k组并进行动态规划:

我们令dp[i][j]表示遍历到第i组状态为j时的最小替换次数,那么直到当前分组所能构成的异或值之和上一个分组的状态有关,我们分两种情况讨论:

首先假设到第i个分组所能组成的异或值为x,并且到上一个分组的组成的异或值为y,那么这个分组需要组成x^y的异或值。

1⃣️假设x^y这个值并没有在第i个分组里出现过,呢最有解一定是上一个分组所有状态中的最小值与当前分组元素个数的和。

2⃣️若x^y这个值在当前分组出现过,那么我们需要枚举上一个状态以及这个分组出现的所有状态,从而寻求最优解!【注:这里我采用set进行优化,因为直接暴力当前状态的话会超时】

class Solution {
    public int minChanges(int[] nums, int k) {
        int m = 1 << 10;
        int n = nums.length;
        int[] dp = new int[m];
        Set[] st = new Set[k];
        int[] size = new int[k];
        int[][] groups = new int[k][m];
        for (int i = 0; i < k; i++)
            st[i] = new HashSet<Integer>();
        for (int i = 0; i < k; i++) {
            for (int j = i; j < n; j += k) {
                groups[i][nums[j]]++;
                st[i].add(nums[j]);
                size[i]++;
            }
        }
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for (int i = 0; i < k; i++) {
            int mn = dp[0];
            for (int j = 0; j < m; j++)
                mn = Math.min(mn, dp[j]);
            int[] dp1 = new int[m];
            Arrays.fill(dp1, mn + size[i]);
            for (int j = 0; j < m; j++) {
                if (dp[j] == Integer.MAX_VALUE)
                    continue;
                Iterator<Integer> it = st[i].iterator();
                while (it.hasNext()) {
                    int val = it.next();
                    dp1[val ^ j] = Math.min(dp1[val ^ j], dp[j] + size[i] - groups[i][val]);
                }
            }
            for (int j = 0; j < m; j++)
                dp[j] = dp1[j];
        }
        return dp[0];
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值