滑动窗口解决子串问题

问题解析:

以这道题为例子:. - 力扣(LeetCode)找长度最小的子数组,子数组和必须大于条件中的target

暴力解法:左右指针列举出每一种子数组的可能,每种可能去求子数组的和,找到最小的子数组。

时间复杂度:On3       左右指针枚举出所有的子数组需要On2的复杂度,再去求每个子数组组的和,总计为On3的复杂度。

暴力枚举的进阶:利用单调性:左指针在最外层循环从左到右进行遍历,右指针每次从左指针开始求和计算找到第一次满足target的子数组,这个数组就是当前左指针下最短数组(单调性)。左指针遍历完数组就能拿到长度最小的子串。

时间复杂度:On2.      不需要通过左右指针去列举出所有的子数组了。只需要左指针进行遍历,然后在左指针的节点从左到右求和即可。

进阶:滑动窗口解决:计算完以当前起始位置的最小子数组后左指针右移时,右指针不用从左指针的位置开始重新计算和了,直接将左指针右移前的和减去左指针原来的位置就可以得到当前子数组的和,直接进行判断,小于target右指针右移、大于target直接记录当前子数组。(也是利用单调性,因为左指针右移,此时子数组的和是缩减的,那么右指针要么不动就可以满足要么需要右移,不可能往左)。

代码:

        int sum = 0;
        int minLn = Integer.MAX_VALUE;
        int left = 0 , right = 0;
        while(right < nums.length) {
            sum += nums[right ++]; //进窗口
            while(sum >= target)  { //判断
                minLn = Math.min(minLn , right - left); //更新结果
                sum -= nums[left ++];//出窗口
            }
        }
        return minLn == Integer.MAX_VALUE ? 0 : minLn;

题目:

. - 力扣(LeetCode)无重复字符最长子串 ****

. - 力扣(LeetCode)最大连续1的个数。****

*****. - 力扣(LeetCode)在数组的前后取值将目标数减到0的最小步数。

题目要求从数组前面或者后面进行操作得到最小步数,俩段是不连续的,但是我们可以将这个问题进行转换数组是固定的,数组和是固定的,你从俩边去最少的和固定的数,此时中间连续一段子数组的和也是固定的且是最长的。

怎么求中间子数组要满足的和的值:数组总和减去目标数。

此时就可以使用我们的滑动窗口计算出中间这段子数组的长度进而求出俩边的长度。

. - 力扣(LeetCode)只能采摘俩种水果,求采摘最多的水果数量,要求必须连续:

        int[] kinds = new int[fruits.length];//下标表示水果种类,值表示对应水果数量
        int kind = 0;//已经采摘的水果种类
        int left = 0;
        int right = 0;
        int maxLen = 0; //最大长度即水果数量
        while(right < fruits.length) {
            kinds[fruits[right]] ++;
            if(kinds[fruits[right]] == 1) kind ++;//如果加之后的值是1说明采摘了新种类
            while(kind > 2) {
                kinds[fruits[left]] --;
                if(kinds[fruits[left]] == 0) kind --;
                left ++;
            }
            maxLen = Math.max(right- left + 1 , maxLen);
            right ++;
        }
        return maxLen;

. - 力扣(LeetCode)找字符串中的所有异位词*******

通过异位词的长度来维护这个窗口。同时维护一个有效字母数量用来确定当前字串是否满足异位词要求。

public List<Integer> findAnagrams(String s, String p) {
        //建立p的哈希
        int[] model = new int[26];
        for(int i= 0;i < p.length();i ++) {
            model[p.charAt(i) - 97] ++;
        }
        int[] hash = new int[26];
        int left = 0;
        int right = 0;
        List<Integer> list = new LinkedList<>();
        int integalCount = 0;//合法字符数量
        while(right < s.length()) {
            //只有model中存在且值大于hash中的值时合法字符数量+1,这样当合法字符数量等于p长度时即为目标子串
            hash[s.charAt(right) - 97] ++;
            if(hash[s.charAt(right) - 97] <= model[s.charAt(right) - 97]) {
                integalCount ++;
            }
            if(right - left + 1 > p.length()) {
                hash[s.charAt(left) - 97] --;
                if(hash[s.charAt(left) - 97] < model[s.charAt(left) - 97]) {
                    integalCount --;
                }
                left ++;
            }
            
            if(integalCount == p.length()) list.add(left);
            right ++;
        }
        return list;
    }

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
滑动窗口算法是一种用于解决一些查找满足一定条件的连续区间的性质的问题的思想或技巧。它可以将双层嵌套的循环问题转换为单层遍历的循环问题,从而降低时间复杂度滑动窗口算法的步骤通常包括维护两个指针left和right,表示当前窗口的左右边界。通过移动右指针扩大窗口,直到窗口内的元素之和满足某个条件。然后,移动左指针缩小窗口,直到不能再缩小为止。在这个过程中,记录窗口的最小长度,并更新最小长度的值。最后返回最小长度。滑动窗口算法的优点包括时间复杂度较低、空间复杂度较低、简单易懂。然而,滑动窗口算法也有一些缺点,包括无法解决所有子串问题、可能存在重复计算和可能存在局限性。总的来说,滑动窗口算法是一种有效的解决特定类型问题的方法。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [滑动窗口算法精讲(Sliding Window Algorithm)](https://blog.csdn.net/qq_39559641/article/details/122793321)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [滑动窗口算法](https://blog.csdn.net/m0_63951142/article/details/130671127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值