OJ刷题日记:3、滑动窗口(1)

简介: OJ刷题日记:3、滑动窗口(1)

一、209.长度最小的数组

题目:

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其总和大于等于 target 的长度最小的 连续

子数组

[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0

示例 1:


输入:target = 7, nums = [2,3,1,2,4,3]

输出:2

解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]

输出:1


示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]

输出:0


首先看下题目,这个题目的意思就是最小连续数组,也就是如示例一中数组,当数组中几个数字的和大于等于target的时候就是正确,但是需要最小的数组,也就是像示例一中2+3+1+2等于8大于target,这就是一个结果,然后3+4也是等于target的时候,就可以返回这两个坐标之间的差,然后这题可以利用双指针进行计算,但是这个双指针不和之前的双指针一样,这里是利用一个同向的双指针,也就是left和right都为0,right就是直至向前走,然后把每个坐标的数据相加,然后这个和大于等于target的时候停下来,然后进行left++,并且把left的数据移除,这个就是滑动窗口的写法,这里是总结了四个点,如下面:


1、left=0,right=0


2、进窗口


3、判断、出窗口


4、更新结果

根据上面四个步骤进行写代码,如下方代码所示,测试通过了,如图,我第一次写框框写了一堆,结果发现利用滑动窗口就可以进行写出来了,这里需要注意len也就是计算数组之间的长度这个是需要最小的,所以这里需要给放个最大值,要不然一直是0,这里的时间复杂度是O(N),因为这里只有right的一趟,left只是少数也就是个常数项,可以忽略不计。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size(),sum=0,len=INT_MAX;
        for(int left=0,right=0;right<n;right++)
        {
            sum+=nums[right];
            while(sum>=target)
            {
                len=min(len,right-left+1);
                sum-=nums[left];
                left++;
            }
        }
        return len==INT_MAX?0:len;
    }
};

二、 3.无重复字符的最长子串

题目:

给定一个字符串 s ,请你找出其中不含有重复字符的 最长

子串

 的长度。

示例 1:

输入: s = "abcabcbb"

输出: 3

解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。


示例 2:

输入: s = "bbbbb"

输出: 1

解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。


示例 3:

输入: s = "pwwkew"

输出: 3

解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

    请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。


提示:


0 <= s.length <= 5 * 104

s 由英文字母、数字、符号和空格组成

首先还是看题目 ,是不判断重复的字符串,这里就是创建了一个数组,数组刚好是128个字符的大小,然后进行判断,也是利用滑动窗口的双指针进行判断,当进窗口的时候直接就可以给这个字符的数组++,当不为1的时候就是重复了,所以当重复的时候,就进行出窗口,直到这个重复的字符出掉,然后更新返回值如下代码所示,这里的时间复杂度也是O(N)。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int c[128]={0};
        int left=0,right=0,n=s.size(),ret=0;
        while(right<n)
        {
            c[s[right]]++;
            while(c[s[right]]>1)
            {
                c[s[left]]--;
                left++;
            }
            ret=max(ret,right-left+1);
            right++;
        }
        return ret;
    }
};

三、1004.最大连续1的个数

题目:

给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 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。


提示:


1 <= nums.length <= 105

nums[i] 不是 0 就是 1

0 <= k <= nums.length

这个题目也是利用滑动窗口进行做的,首先left和right为0,然后进窗口不过这里题目说了反转0,第一开始我想的也是反转0,后来发现完全没必要,这里可以直接定义一个变量然后进行++,也就是当判断到0的时候直接取反然后k1++,当k1大于k的时候就可以进行出窗口了,也就是k1--,然后更新结果,代码如下,这里的时间复杂度也是O(N)。

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int left=0,right=0,n=nums.size(),ret=0,k1=0;
        while(right<n)
        {
            if(!nums[right])
            k1++;
            while(k1>k)
            {
                if(!nums[left])
                k1--;
                left++;
            }
            ret=max(ret,right-left+1);
            right++;
        }
        return ret;
    }
};

四、1658.将x减到0的最小操作数


题目:


给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。

如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1

示例 1:

输入:nums = [1,1,4,2,3], x = 5

输出:2

解释:最佳解决方案是移除后两个元素,将 x 减到 0 。


示例 2:

输入:nums = [5,6,7,8,9], x = 4

输出:-1


示例 3:

输入:nums = [3,2,20,1,1,3], x = 10

输出:5

解释:最佳解决方案是移除后三个元素和前两个元素(总共 5 次操作),将 x 减到 0 。


提示:


1 <= nums.length <= 105

1 <= nums[i] <= 104

1 <= x <= 109

首先看到这个题目我也就是想到了滑动窗口的做法,首先还是left和right为0,然后进行进窗口,但是这个题目我做的时候挺烦的,因为他一会左一会右,然后我就在想滑动窗口能做不?但是后来发现这题完全可以用一个正难则反的原理,就是我不找减去的,我找一个总和减去x相等的连续数组,就可以转化成本章第一题了,然后实操试一下,中间部分没啥说的,还是小于进窗口大于出窗口,等于更新结果,然后提交,发现错了?,后来发现是因为我这里用来计算总和减去x的值小于0,这种情况在,在进入了循环也是错的,所以这里是提前判断然后返回-1,代码如下时间复杂度也是O(N)。

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int left=0,right=0,ret=-1,target=0,n=nums.size(),sum=0;
        for(auto e:nums)
            target+=e;
        target-=x;
        if(target<0)
        return -1;
        while(right<n)
        {
            sum+=nums[right];
            while(sum>target)
            {
                sum-=nums[left];
                left++;
            }
            if(sum==target)
            {
                ret=max(ret,right-left+1);
            }
            right++;
        }
        return ret==-1?ret:n-ret;
    }
};

目录
相关文章
|
18天前
|
算法 容器
OJ刷题日记:2、双指针(2)
OJ刷题日记:2、双指针(2)
17 0
|
18天前
|
算法 搜索推荐 测试技术
【刷题】 滑动窗口进阶
这样的优化对于该题的提升是有限的,但是这是一种非常实用的算法,以后还会遇见哦!!!
15 0
|
18天前
|
算法 C++ 索引
OJ刷题日记:4、滑动窗口(2)
OJ刷题日记:4、滑动窗口(2)
17 0
|
18天前
|
算法 测试技术
OJ刷题日记:1、双指针(1)
OJ刷题日记:1、双指针(1)
22 0
|
18天前
|
算法 索引
OJ刷题日记:5、二分查找(1)
OJ刷题日记:5、二分查找(1)
25 0
|
18天前
|
机器学习/深度学习 算法
六六力扣刷题双指针之三数之和
六六力扣刷题双指针之三数之和
35 0
|
18天前
剑指Offer LeetCode 面试题59 - I. 滑动窗口的最大
剑指Offer LeetCode 面试题59 - I. 滑动窗口的最大
22 0
|
11月前
|
Cloud Native
【刷题日记】64. 最小路径和
本次刷题日记的第 39 篇,力扣题为:64. 最小路径和 ,中等
|
11月前
|
Cloud Native
【刷题日记】70. 爬楼梯
本次刷题日记的第 10 篇,力扣题为:70. 爬楼梯 ,简单
|
11月前
|
算法 测试技术 Cloud Native
【刷题日记】2104. 子数组范围和
对于很久没有刷题的我来说,突然开始也开始刷题了,不为别的,已经习惯参与掘金的活动了,同时也可以促进自己再回顾一下算法题,毕竟长时间不练,真的就生疏了