995. K连续位的最小翻转次数

一、题目

在这里插入图片描述

二、思路

2.1 解题思路

就是滑动窗口一个一个遍历,遇到情况就翻转。最后检查所有的是否还出现0.

2.2 代码尝试

class Solution {
public:
    int minKBitFlips(vector<int>& nums, int k) {
        int sum=0;
        int t=k;
        for(int i=0;i<=nums.size()-k;i++){
            if(nums[i]==1){
                continue;
            }else{
                if(k==1){
                    nums[i]=1;
                }else{
                    t=k;
                    while(t>0){
                        nums[i+t-1] & 1;
                        t--;
                    }
                }
                sum++;
            }
        }
        if(nums[nums.size()-1]==0){
            return -1;
        }
        return sum;
    }
};

翻转操作未正确实现:

你在 while(t>0) 循环中对 nums[i+t-1] 进行了按位与操作 & 1,但这个操作并没有实际改变 nums[i+t-1] 的值。你应该是想对数组元素进行翻转(0变1,1变0),但你没有实现这个逻辑。

边界条件处理不足:

你在最后检查了 nums[nums.size()-1] 是否为0,但如果在数组的末尾有多个0,你的代码可能无法正确处理。
在这里插入图片描述
这种就没法判断

时间复杂度较高:

你的代码在最坏情况下时间复杂度为 O(n*k),这在某些情况下可能会导致性能问题。

2.3 疑难问题

在这里插入图片描述
感觉思路没问题,但有边界问题
如何进行翻转0-1操作?如何减小时间复杂度?for循环太多了,感觉思路上还可以优化

三、解法

class Solution {
public:
    int minKBitFlips(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> diff(n + 1);
        int ans = 0, revCnt = 0;
        for (int i = 0; i < n; ++i) {
            revCnt += diff[i];
            if ((nums[i] + revCnt) % 2 == 0) {
                if (i + k > n) {
                    return -1;
                }
                ++ans;
                ++revCnt;
                --diff[i + k];
            }
        }
        return ans;
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/minimum-number-of-k-consecutive-bit-flips/solutions/607416/k-lian-xu-wei-de-zui-xiao-fan-zhuan-ci-s-bikk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

好的!我们以数组 nums = [0, 0, 0, 1, 0, 1, 1, 0]k = 3 为例,逐步展示代码中主要变量的变化过程。


代码逻辑回顾

  1. diff 数组

    • 用于记录翻转操作的影响范围。
    • diff[i] 表示从位置 i 开始的翻转操作的影响。
  2. revCnt

    • 记录当前位置 i 的翻转次数(即当前处于多少次翻转的影响下)。
  3. ans

    • 记录总的翻转次数。
  4. 核心逻辑

    • 遍历数组,检查当前元素是否需要翻转。
    • 如果需要翻转,则更新 revCntdiff,并增加 ans

示例运行过程

初始状态:
nums = [0, 0, 0, 1, 0, 1, 1, 0]
n = 8
k = 3
diff = [0, 0, 0, 0, 0, 0, 0, 0, 0]  // 大小为 n + 1
ans = 0
revCnt = 0
遍历过程:
  1. i = 0

    • revCnt += diff[0]revCnt = 0
    • nums[0] + revCnt = 0 + 0 = 00 % 2 == 0,需要翻转。
    • 检查 i + k = 3 是否越界 → 3 <= 8,可以翻转。
    • 更新:
      • ans = 1
      • revCnt = 1
      • diff[3] = -1
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, 0, 0]
      ans = 1
      revCnt = 1
      
  2. i = 1

    • revCnt += diff[1]revCnt = 1 + 0 = 1
    • nums[1] + revCnt = 0 + 1 = 11 % 2 != 0,不需要翻转。
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, 0, 0]
      ans = 1
      revCnt = 1
      
  3. i = 2

    • revCnt += diff[2]revCnt = 1 + 0 = 1
    • nums[2] + revCnt = 0 + 1 = 11 % 2 != 0,不需要翻转。
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, 0, 0]
      ans = 1
      revCnt = 1
      
  4. i = 3

    • revCnt += diff[3]revCnt = 1 + (-1) = 0
    • nums[3] + revCnt = 1 + 0 = 11 % 2 != 0,不需要翻转。
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, 0, 0]
      ans = 1
      revCnt = 0
      
  5. i = 4

    • revCnt += diff[4]revCnt = 0 + 0 = 0
    • nums[4] + revCnt = 0 + 0 = 00 % 2 == 0,需要翻转。
    • 检查 i + k = 7 是否越界 → 7 <= 8,可以翻转。
    • 更新:
      • ans = 2
      • revCnt = 1
      • diff[7] = -1
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, -1, 0]
      ans = 2
      revCnt = 1
      
  6. i = 5

    • revCnt += diff[5]revCnt = 1 + 0 = 1
    • nums[5] + revCnt = 1 + 1 = 22 % 2 == 0,需要翻转。
    • 检查 i + k = 8 是否越界 → 8 <= 8,可以翻转。
    • 更新:
      • ans = 3
      • revCnt = 2
      • diff[8] = -1
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, -1, -1]
      ans = 3
      revCnt = 2
      
  7. i = 6

    • revCnt += diff[6]revCnt = 2 + 0 = 2
    • nums[6] + revCnt = 1 + 2 = 33 % 2 != 0,不需要翻转。
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, -1, -1]
      ans = 3
      revCnt = 2
      
  8. i = 7

    • revCnt += diff[7]revCnt = 2 + (-1) = 1
    • nums[7] + revCnt = 0 + 1 = 11 % 2 != 0,不需要翻转。
    • 状态:
      diff = [0, 0, 0, -1, 0, 0, 0, -1, -1]
      ans = 3
      revCnt = 1
      

最终结果

  • 总翻转次数 ans = 3
  • 最终数组状态(如果实际翻转):
    nums = [1, 1, 1, 1, 1, 1, 1, 1]
    

总结

通过这个例子,我们可以看到:

  1. diff 数组用于记录翻转操作的影响范围。
  2. revCnt 用于动态计算当前位置的翻转次数。
  3. 每次翻转操作都会更新 diffrevCnt,从而高效地处理区间翻转。

希望这个详细的例子能帮助你理解代码的运行过程!如果还有疑问,欢迎继续提问!

四、收获

4.1 心得

0-1翻转可以使用异或操作
^= 1
太难了,这道题
用一个标记符号和差分数组。差分数组的累加代表当前元素值
当前元素与标记符号的和,如果是偶数,代表需要翻转。标记符号是1,代表已经翻转的状态。如果元素为1,。标记符号为0,代表未翻转,若元素为0,那么就需要进行翻转的操作,并将范围之外的第一个元素的差分数组置为-1。因为置为-1,这样范围之外的第一个元素与标记符相加,才能重新使得标记符变为0,回到未翻转的状态。
这么精妙的思路,第一次做完全想不到。我只会暴力贪心。但是感觉标记符号和差分数组也是一种模板的公式化解题思路,可能做多了就知道。

4.2 举一反三

遇到0-1翻转的这种需要频繁更新值的,使用标记符号和差分数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海绵波波107

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值