前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初识算法 · 滑动窗口(2)

初识算法 · 滑动窗口(2)

作者头像
_lazy
发布2024-10-16 14:44:50
960
发布2024-10-16 14:44:50
举报
文章被收录于专栏:Initial programming

前言:

本文的主题是滑动窗口,通过两道题目讲解,一道是最大连续1的个数,一道是将x减到0的最小操作数。

链接分别为:

1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode)

1004. 最大连续1的个数 III - 力扣(LeetCode)

题目分为三个部分讲解,一是题目解析,二是算法原理,三是算法编写,那么,话不多说,直接进行主题咯。

最大连续1的个数III

题目解析

我们拥有一个数组,数组里面的值非0即1,还给了我们一个整数k,代表我们可以翻转最多k个0,要求返回的值是连续1的最大个数。

那么根据示例呢,我们也清楚了,需要我们选定一个头,从头开始,遍历数组,途中找到零可以反转,只要不超过个数就可以,反转之后,判断该长度是否为最长的连续1数组,比如示例1,两个0加后面的4个1,刚好符合条件,所以我们返回的是6,这是我们需要做的。

那么照例,暴力解法我们放在该部分介绍。

有没有暴力解法呢?当然是有的,我们无非就是从数组下标为0的地方开始,一直往后走,有零看能不能反转,如果可以翻转就继续往下走,不可以就存储该长度,最后返回所有长度的最大值就可以了。

暴力解法的时间复杂度是标准的O(N^2),这道题也是可以通过的,具体编写呢就给同学们啦。

基本题目我们已经清楚了,现在我们就进行算法原理部分。

算法原理

我们这道题目使用的是滑动窗口,那么为什么使用滑动窗口呢?或者说为什么我们根据题目解析一看就知道要使用滑动窗口呢?

因为该题目的基本要求是一个连续的数组,也就是需要一段连续的空间,所以我们基本上可以断定为使用滑动窗口。

好了,既然需要使用滑动窗口,我们的三部曲,进窗口,出窗口,更新结果

进窗口肯定是需要right来进的,进的时候需要注意的肯定只有0了,所以我们需要一个zero计时器,如果进窗口的时候是0,那么countzero++,出窗口的前提就是判断,判断的条件自然是如果countzero > k,也就是翻转的0上限了,所以需要出数据了,出肯定是left++,当left等于0的时候,即碰到0,此时left++,并且countzero--,就可以成功出掉数据。

此时,更新结果,一套流程下来,就没有啦。

算法编写

代码语言:javascript
复制
class Solution
{
public:
    int longestOnes(vector<int>& nums, int k) 
    {
        int countzero = 0, ans = 0;
        for(int left = 0, right = 0; right < nums.size(); right++)
        {
            if(nums[right] == 0) countzero++; //进窗口
            while(countzero > k)//判断 + 出窗口
                if(nums[left++] == 0) countzero--;
            ans = max(ans,right - left + 1);
        }
        return ans;
    }
};

根据代码的编写,时间复杂度接近N的,但是肯定还是小于暴力解法的,空间复杂度是O(1),毕竟没有额外的开空间。


将x减到0的最小操作数

题目解析

题目要求和往常的稍微有点不一样,移除的元素不是数组中间的元素,而是数组最左边或者数组最右边的元素,选择最左边或最右边的值,x减去该值,最后x等于0返回的是减去的最小操作值。

这题目一看好像和滑动窗口没有关联,但是,题目特殊点在于减去的是最左边或者最右边的值。

那么我们不妨,将题目改造成,求一段区间,该区间的值等于该数组的总和 - x。

那么暴力解法就很简单了,两个循环,确定一个起点,然后遍历,用一个变量存储值,然后比较即可。

时间复杂度也是标准的O(N^2),优化就和之前一摸一样了,优化之后就是滑动窗口了。

算法原理

其实本题的算法原理在题目解析部分就已经介绍的七七八八了,无非就是一段区间,进窗口,变量++,判断变量是否大于target,大于就--,最后判断变量是否==0,如果等于0,更新结果就可以了,其实这道题还没有第一题难。

如果不逆向思维,那么这道题还是挺难做的。

算法编写

代码语言:javascript
复制
class Solution
{
public:
    int minOperations(vector<int>& nums, int x) 
    {
        int sum = 0;
        for(int a : nums) sum += a;
            int target = sum - x;
        // 细节问题
        if(target < 0) return -1;
        int ret = -1;
        for(int left = 0, right = 0, tmp = 0; right < nums.size(); right++)
        {
            tmp += nums[right]; // 进窗⼝
            while(tmp > target) // 判断
            tmp -= nums[left++]; // 出窗⼝
            if(tmp == target) // 更新结果
            ret = max(ret, right - left + 1);
        }
        if(ret == -1) return ret;
        else return nums.size() - ret;
        }
};

时间复杂度也是接近O(N)了。空间复杂度为O(1),毕竟没有多开空间。

感谢阅读!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 最大连续1的个数III
    • 题目解析
      • 算法原理
        • 算法编写
        • 将x减到0的最小操作数
          • 题目解析
            • 算法原理
              • 算法编写
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档