算法通关村-----滑动窗口高频问题

发布于:2023-09-14 ⋅ 阅读:(173) ⋅ 点赞:(0)

无重复字符的最长子串

问题描述

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

问题分析

可以通过滑动窗口中的可变窗口思想来解决。设置两个指针,初始时left指向字符串的起始位置,right指向left的下一个位置。设置一个map,key是遍历到的字符,value是字符的下标,right不断向右移动,直到遇到重复字符或者遍历到字符串末尾。遇到重复字符后,记录长度,设置left为重复字符的下一个字符,继续遍历。直至right遍历到字符串末尾。详见leetcode3

代码实现

public int lengthOfLongestSubstring(String s) {
    if(s.length()==0||s.length()==1){
        return s.length();
    }
    Map<Character,Integer> map = new HashMap<Character,Integer>();
    int left=0;
    int right=1;
    int res=1;
    map.put(s.charAt(left),left);
    while(right<s.length()){
        if(map.containsKey(s.charAt(right))){
            left = Math.max(map.get(s.charAt(right))+1,left);
        }
        map.put(s.charAt(right),right);
        right++;
        if(right-left>res){
            res = right-left;
        }
    }
    return res;
}

长度最小的子数组

问题描述

给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0。详见leetcode209

问题分析

这是一道可变窗口问题,目的是找到最小窗口,使窗口内数据大于或者等于target。我们可以首先将left指针放在数组起始处,不断移动right指针,使窗口内数据相加大于等于target,之后可以移动left指针,直至窗口内数据之和小于target,在不断移动right指针,重复这个过程,记录下每一个满足条件的窗口大小,直至right指针移向数组末尾。返回可变窗口最小值。

代码实现

public int minSubArrayLen(int target, int[] nums) {
    int minLen = Integer.MAX_VALUE;
    int left=0;
    int right=0;
    int sum=0;
    while(right<nums.length){
        sum += nums[right++];
        while(sum>=target){
            minLen = Math.min(minLen,right-left);
            sum-=nums[left++];
        }
    }
    if(minLen==Integer.MAX_VALUE){
        return 0;
    }else{
        return minLen;
    } 
}

盛水最多的容器

问题描述

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明:你不能倾斜容器。详见leetcode11

问题分析

这是一个可变窗口问题。初始时,我们可以设置两个指针left和right指向数组0和n-1的位置,储水量为Math.min(height[right],hight[left])*(right-left),这就是短板效应。之后我们考虑两个指针向内移动,right-left一定会减小,当移动高度较大的指针时,高度也会变小,所以,我们只能移动高度小的指针。

代码实现

public int maxArea(int[] height) {
    if(height.length==0||height.length==1){
        return 0;
    }
    int left = 0;
    int right = height.length-1;
    int waterNum = 0;
    while(left<right){
        int num = Math.min(height[right],height[left])*(right-left);
        waterNum = Math.max(num,waterNum);
        if(height[right]>height[left]){
            left++;
        }else{
            right--;
        }
    }
    return waterNum;
}

字符串的排列

问题描述

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。换句话说,s1 的排列之一是 s2 的 子串 。s1 和 s2 仅包含小写字母。详见leetcode567

问题分析,这是一个固定窗口问题。固定窗口大小为s1的长度,大小为s1长度的窗口在s2滑动,统计每个窗口中的字母种类和数量与s1是否一致,一致返回true,不一致继续扫描,直至right指针指向字符床末尾,还未扫描到,返回false。

public boolean checkInclusion(String s1, String s2) {
    int[] chars1 = new int[26];
    int[] chars2 = new int[26];
    int n = s1.length();
    int left = 0;
    int right = n-1;
    for(int i=0;i<n;i++){
        int index = s1.charAt(i)-'a';
        chars1[index]++;
    }
    while(right<s2.length()){
        for(int i=left;i<=right;i++){
            int index = s2.charAt(i)-'a';
            chars2[index]++;
        }
        if(Arrays.equals(chars1,chars2)){
            return true;
        }else{
            left++;
            right++;
            for(int i=0;i<26;i++){
                chars2[i] = 0;
            }
        }
    }
    return false;
}
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到