3.LeetCode刷题记录[数组]滑动窗口(双指针)

本文介绍了滑动窗口算法在解决数组中最长子数组长度和最大水果数量问题中的应用。通过实例解析了如何使用滑动窗口模板来找到满足条件的子数组,并给出了不同解法的比较,包括O(n)和O(nlog(n))时间复杂度的解决方案。同时,文章探讨了如何优化解题思路,降低空间复杂度。
摘要由CSDN通过智能技术生成

接下来学习的知识是数组中的滑动窗口

还是按照之前的思路 先学习滑动窗口的思路

还是之前的哪个人的教程 我觉得很通俗易懂

滑动窗口就是这么神奇!​mp.weixin.qq.com/s/ewCRwVw0h0v4uJacYO7htQ

紧接着做第一道题:

解题思路我都放在了程序里面

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
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //滑动窗口的初始位置 初始指针的位置
        int startPointer = 0;//表示指针的初始位置从0序号开始
        int sum = 0;//定义sum用来存储子数组的和
        /**
         * 刚开始定义的是0
         * 后面结合后面的判断发现
         * 如果是0的话不好进行最小子数组的判断
         */
        int result = Integer.MAX_VALUE;//用于存储子数组的长度
        
        //遍历数组 相当于快指针  前面定义的初始指针相当于慢指针
        for(int fastPointer = 0;fastPointer<nums.length;fastPointer++){
            sum += nums[fastPointer];
            while(sum>=target){
                //求得子数组的长度
                int numsLength = fastPointer - startPointer + 1;//长度记得+1
                result = numsLength<result?numsLength:result;
                //相当于将左窗口的位置向前移动一位,然后得到移动后
                //的子数组的大小
                sum -= nums[startPointer++];
            }
        }
        return result==Integer.MAX_VALUE?0:result;
    }
}

904. 水果成篮

在一排树中,第 i 棵树产生 tree[i] 型的水果。
你可以从你选择的任何树开始,然后重复执行以下步骤:

把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
移动到当前树右侧的下一棵树。如果右边没有树,就停下来。
请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。
你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。
用这个程序你能收集的水果树的最大总量是多少?
示例 1:
输入:[1,2,1]
输出:3
解释:我们可以收集 [1,2,1]。
示例 2:
输入:[0,1,2,2]
输出:3
解释:我们可以收集 [1,2,2]
如果我们从第一棵树开始,我们将只能收集到 [0, 1]。
示例 3:
输入:[1,2,3,2,2]
输出:4
解释:我们可以收集 [2,3,2,2]
如果我们从第一棵树开始,我们将只能收集到 [1, 2]。
示例 4:
输入:[3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:我们可以收集 [1,2,1,1,2]
如果我们从第一棵树或第八棵树开始,我们将只能收集到 4 棵水果树。
提示:
1 <= tree.length <= 40000
0 <= tree[i] < tree.length
class Solution {
    public int totalFruit(int[] fruits) {
        if(fruits.length == 0){
            return 0;
        }
        else if(fruits.length == 1){
            return 1;
        }
        int Length = 0;//总量数组的s
        int maxLength = 0;
        int basket[] = {Integer.MAX_VALUE,Integer.MAX_VALUE};//定义两个篮子
        //定义一个快指针 用于遍历数组

        for (int startPointer = 0; startPointer < fruits.length-1; startPointer++) {
            int endPointer = startPointer+1;
            basket[0] = fruits[startPointer];
            /**
             * 一开始我是打算将全部都是一个小窗口(当前的数和他下一个数组成一个窗口)
             * 但是还需要判断初始两端直接相等的情况
             * 这一部分我还没有考虑很好
             */
            for(int i= endPointer;i<fruits.length;i++){
                if(basket[0]!=fruits[i]){
                    endPointer = i;
                    basket[1] = fruits[endPointer];
                    break;
                }
                else{

                }
            }
            //判断窗口的结束位置右边的数有没有相同
            for (int fastPointer = endPointer+1; fastPointer < fruits.length; fastPointer++) {
                if(fruits[fastPointer] == basket[0]||fruits[fastPointer] == basket[1]){
                    endPointer++;//如果有那么窗口扩充
                }
                else{
                    break;
                }
            }
            Length = endPointer - startPointer +1;
            if(maxLength<Length){
                maxLength = Length;
            }
            if(maxLength == fruits.length){//最长的直接结束
                break;
            }
            //如果剩余的数组长度已经没有maxlength大 那么直接结束
            if(startPointer>=fruits.length/2&&maxLength>=fruits.length){
                break;
            }
        }

        return maxLength;
    }
}

这种方法的排名不高 我晚上看看别人的解题思路

参考别人的解题思路:

1.题目意思

每棵树只有1个水果。

找出连续子数组,一共2种水果,子数组长度最长。

2.思路

求最长子数组长度,直滑动窗口模板。

最长窗口模板

for(枚举选择)
右边界
while(不符合条件)
左边界
更新结果
思路:
本题中符合条件指窗口中水果种类是2。
用HashMap记录,Map<水果种类,出现频次>,
延伸右边界时,增加频次。缩进左边界时,减少频次。
频次为0时,从map删除。
map的大小为2时,正好符合条件。
这种套用模板的方式 算法的时间复杂度有所增加 但是空间复杂度降低了
class Solution {
    public int totalFruit(int[] fruits) {
        //对数组进行简单的判断 判断它是不是为null 或者 没有
        if(fruits==null||fruits.length==0){
            return 0;
        }
        int maxLength = 0;//定义最大的长度
        int leftIndex = 0;//定义左边的边界
        
        //定义篮子
        /**
         * 前面一个Interger保存树的编号
         * 后面一个Interger保存同种类型的数量
         */
        Map<Integer,Integer> basket= new HashMap<>();

        //枚举选择
        //有边界
        for (int rightIndex = 0; rightIndex < fruits.length; rightIndex++) {
             //判断在篮子里面是不是已经有了这种编号的树
            basket.put(fruits[rightIndex], basket.getOrDefault(fruits[rightIndex], 0)+1);
            while(basket.size()>2){
                basket.put(fruits[leftIndex], basket.get(fruits[leftIndex])-1);//慢慢移动左边窗口
                if(basket.get(fruits[leftIndex])==0) basket.remove(fruits[leftIndex]);
                leftIndex++;
            }
            maxLength = Math.max(maxLength, rightIndex-leftIndex+1);
        }

        return maxLength;
    }
}

76. 最小覆盖子串

字符串的题暂时不做
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:
输入:s = "a", t = "a"
输出:"a"
示例 3:
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
提示:
1 <= s.length, t.length <= 105
s 和 t 由英文字母组成
进阶:你能设计一个在 o(n) 时间内解决此问题的算法吗?

总结:滑动窗口用于求解

最长子数组长度。

题目来源:

来源:力扣(LeetCode)

链接:力扣

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值