【LeetCode刷题笔记】(五)滑动窗口

239 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情 这也是第39篇文章

前言

这篇文章的主题是——滑动窗口。

是什么

首先简要说说什么是滑动窗口。

这个“窗口”是一个假想的概念,它有固定的范围,但它前后边界指向的地方会变化,就像滑动了一样,因此称为 滑动窗口 。

以下是一个很简单、直观的入门级解释。

以数组[1,2,3]为例,有一个大小为2的滑动窗口,一开始窗口框住了1,2,后来窗口往前移动了一位,框住了[2,3]。它就像滑动了一样。

image.png

滑动窗口也可理解为是距离保持不变的双指针。

有什么用

从我做过的题来看,可以简化搜索、确定范围等等。

剑指 Offer 48. 最长不含重复字符的子字符串

题目

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

思路

这个子字符串的区间就可以看做是一个窗口,因此可以用滑动窗口的思想去做。i作为左指针,r作为右指针,当右指针遇到重复字符时,左指针跳到子串里第一个重复字符的位置,并通过set把子串中重复字符前的字符去掉,右指针继续往右扩展。

代码实现

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n=s.length();
        int res=0,r=-1;
        HashSet<Character> set=new HashSet<>();
        for(int i=0;i<n;i++){
            if(i!=0) set.remove(s.charAt(i-1));
            while(r+1<n&&!set.contains(s.charAt(r+1))){
                set.add(s.charAt(r+1));
                r++;
            }
            res=Math.max(res,r-i+1);
        }
        return res;
    }
}

剑指 Offer II 009. 乘积小于 K 的子数组

题目

给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。

思路

和第一题类似,右指针每次都往右扩展,如果遇到不符合条件的情况,就缩短左区间。

每次区间的大小就是这一轮包含的子数组的个数。

代码实现

class Solution {
    public int numSubarrayProductLessThanK(int[] nums, int k) {
        int cnt=0;
        int n=nums.length;
        int tmp=1;
        int i=0,j=0;
        while(j<n){
            tmp*=nums[j];
            while(i<=j&&tmp>=k){
                tmp/=nums[i];
                i++;
            }
            cnt+=(j-i)+1;
            j++;
        }
        return cnt;
    }
}