滑动窗口_最大连续1的个数|||_C++

1.题目解析


leedcode题目链接:https://leetcode.cn/problems/max-consecutive-ones-iii/submissions/

给定一个二进制数组 nums和一个整数 k,如果可以翻转最多 k0 ,则返回数组中连续 1 的最大个数 。

示例 1:

输入:nums = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。

示例 2:

输入:nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。


2.算法原理


2.1解法一:暴力枚举+zero计数器


如果我们真的按题目中的理解,让0翻转成1的话,将会非常麻烦。我们可以将问题转化成:找出最长的连续子数组,0的个数不超过k个。我们可以设置一个zero来记录0出现了多少次。

以:[1,1,1,0,0,0,1,1,1,1,0]k = 2为例:

在这里插入图片描述

我们先定义两个指针,left记录起始位置,right记录终止位置。最开始时,leftright都指向下标为0的位置。如果right指向的数据为1,就直接让right++,跳过这个数据;如果为0,就让zero++,然后再让right++,表示0又出现了一次。如图,当right指向图中位置时,zero的值已经为2了,且当前位置的值是0,说明已经找到了一个结果,记录这个结果。

随后我们可以让left++,让right = left,接着以下标为1的位置为起始位置,再遍历一次,就这样,遍历出最终结果。

2.2解法二:滑动窗口


优质的算法往往都是依据暴力枚举法优化而来的。还是以[1,1,1,0,0,0,1,1,1,1,0]k = 2为例:

在这里插入图片描述

当找到一个结果后,指针指向图中的位置。这时,我们还需要让left++,然后让right回退吗?答案是不需要。

不需要的原因是,我们遇到了一串连续的0,不管left指针从前三个1的那一个1开始遍历,都没有第一个1的结果大,right指针都会在连续的0处终止。这时,我们的思路就是,跳过这串连续的0。

我们固定right不动,让left一直++,遇到1直接跳过,遇到0就让zero--,表示窗口中的0减少了一个。我们一直让left移动到连续的0的第二个0处,从这个0开始移动right,再去寻找下一个结果。


3.代码演示


1.写法1:

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) 
    {
        int left = 0, right = 0;
        int n = nums.size();
        int ret;
        int zero = 0;                       // 记录0出现的次数

        while(right < n)
        {
            while(right < n && (nums[right] || zero < k))      // 进窗口
            {
                if(!nums[right]) zero++;
                right++;
            }

            ret = max(ret, right - left);             // 更新结果

            while(left < n && zero >= k)                     // 出窗口
            {
                if(!nums[left]) zero--;
                left++;
            }
        }

        return ret;
    }
};

2.写法2:

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) 
    {
        int ret = 0;
        for(int left = 0, right = 0, zero = 0; right < nums.size(); right++)
        {
            if(nums[right] == 0) zero++; // 进窗口
            while(zero > k) // 判断
                if(nums[left++] == 0) zero--; // 出窗口
            ret = max(ret, right - left + 1); // 更新结果
        }

        return ret;
    }
};

这两个写法的本质是一样的,都是滑动窗口的原理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

-指短琴长-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值