算法--滑动窗口(二)

算法原理

滑动窗口

算法思路:

问题分析的对象一般是一段连续的区间

这个窗口寻找的是:以当前窗口最左侧元素(left1)为基准,符合条件的情况找到right,此时是left1的最优解

那么我们就可以大胆的把left1舍去,那么我们left右移,如果让right从头开始必然会有很多重复的计算,我们就可以让right先不动,如果不满足要求,那么right++,则可知left和right是同向移动的,不回退的,所以时间复杂度是O(N)

题目解析

https://leetcode.cn/problems/fruit-into-baskets/description/

1.水果成篮

题目解析

果树用fruits表示,fruits[i]是第i棵水果种类

要求:两个篮子,一个篮子一种水果,数量不限,每棵树上恰好摘一种,返回可以收集水果的最大数目

转换:找出最长的子数组(不超过两种水果)

算法原理

解法一:暴力枚举+哈希表

解法二:滑动窗口

代码实现

复制代码
class Solution {
    public int totalFruit(int[] f) {
       int n=f.length;
       int[] hash=new int [n+1];
       int ret=0;
       for(int left=0,right=0,kinds=0;right<n;right++){
        int in=f[right];
        if(hash[in]==0){
            kinds++;
        }
        hash[in]++;
        while(kinds>2){
            int out=f[left];
            hash[out]--;
            if(hash[out]==0){
                kinds--;
            }
            left++;
        }
        ret=Math.max(ret,right-left+1);
       }
       return ret;
    }
}

2.找到字符串中所有字母的异位词

https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/

题目解析

给定字符串s和p,找到s中所有p的异位词子串,返回这些子串的起始索引

算法原理

解法一:暴力解法

解法二:滑动窗口+哈希表(注意这里滑动窗口的大小固定,为p的大小)

优化:更新结果的判断,在用哈希表的时候需要将两个哈希表中的每个元素进行对比

我们可以对这一点进行优化,利用变量count来统计窗口中"有效字符的个数"(那我们在进出,更新的时候都要进行维护)

代码实现

复制代码
class Solution {
    public List<Integer> findAnagrams(String ss, String pp) {
        List<Integer> ret=new ArrayList<>();
        char[] s=ss.toCharArray();
        char[] p=pp.toCharArray();
        int[] hash1=new int[26];
        for(char c:p){
            hash1[c-'a']++;
        }
        int m=p.length;
        int[] hash2=new int [26];
        for(int left=0,right=0,count=0;right<s.length;right++){
            char in=s[right];
            if(++hash2[in-'a']<=hash1[in-'a']){
                count++;
            }
            if(right-left+1>m){
                char out=s[left++];
                if(hash2[out-'a']--<=hash1[out-'a']){
                    count--;
                }
            }
            if(count==m){
                ret.add(left);
            }
        }
        return ret;
    }
}

3.串联所有单词的子串

https://leetcode.cn/problems/substring-with-concatenation-of-all-words/description/

题目解析

给定一个字符串s和一个数组words(所有字符串长度相同)

s中的串联子串是指一个包含words中所有字符串以任意顺序排列连接起来的子串,返回所有串联子串在s中的索引(这个类似找出字母异位词)

算法原理

与上题类似

注意:1.哈希表<String,int> 2.left right的移动left和right移动的是一个单词的长度

3.滑动窗口执行次数(len次)

代码实现

复制代码
class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
       List<Integer> ret=new ArrayList<>();
       Map<String,Integer> hash1=new HashMap<String,Integer>();
       for(String str:words){
        hash1.put(str,hash1.getOrDefault(str,0)+1);
       }
       int len=words[0].length(),m=words.length;
       for(int i=0;i<len;i++){
           Map<String,Integer> hash2=new HashMap<String,Integer>();
           for(int left=i,right=i,count=0;right+len<=s.length();right+=len){
             String in=s.substring(right,right+len);
              hash2.put(in,hash2.getOrDefault(in,0)+1);
             if(hash2.get(in)<=hash1.getOrDefault(in,0))count++;
             if(right-left+1>m*len){
              String out=s.substring(left,left+len);
               if(hash2.get(out)<=hash1.getOrDefault(out,0)){
                count--;
             }
              left+=len;
               hash2.put(out,hash2.get(out)-1);
              
             }
              if(count==m){
                ret.add(left);
              }
          }
       }
       return ret;
    }
}

4.最小覆盖子串

https://leetcode.cn/problems/minimum-window-substring/description/

题目解析

给定字符串s,t,返回s中涵盖t的所有字符的最小子串

算法原理

法一:暴力解法,可以借助HashMap

法二:滑动窗口+哈希表

在此基础上我们可以对判断条件进行优化,使用count来标记有效字符的种类

代码实现

复制代码
class Solution {
    public String minWindow(String ss, String tt) {
        char[] s=ss.toCharArray();
        char[] t=tt.toCharArray();
        int[] hash1=new int[128];
        int kinds=0;
        for(char c:t){
            if(hash1[c]++==0){
                kinds++;
            }
        }
        int[] hash2=new int[128];
        int begin=-1,minlen=Integer.MAX_VALUE;
        for(int left=0,right=0,count=0;right<s.length;right++){
            char in=s[right];
            if(++hash2[in]==hash1[in]){
                count++;
            }
            while(count==kinds){
                if(right-left+1<minlen){
                    begin=left;
                    minlen=right-left+1;
                }
                char out=s[left++];
                if(hash2[out]--==hash1[out]){
                    count--;
                }
            }
        }
        if(begin==-1){
            return new String();
        }else{
            return ss.substring(begin,begin+minlen);
        }
    }
}
相关推荐
吃好睡好便好5 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
仰泳之鹅5 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
x_yeyue7 小时前
三角形数
笔记·算法·数论·组合数学
念何架构之路9 小时前
Go语言加密算法
数据结构·算法·哈希算法
AI科技星9 小时前
《数学公理体系·第三部·数术几何》(2026 年版)
c语言·开发语言·线性代数·算法·矩阵·量子计算·agi
失去的青春---夕阳下的奔跑9 小时前
560. 和为 K 的子数组
数据结构·算法·leetcode
黎阳之光9 小时前
黎阳之光:以视频孪生重构智慧医院信息化,打造高标项目核心竞争力
大数据·人工智能·物联网·算法·数字孪生
丷丩10 小时前
三级缓存下MVT地图瓦片服务性能优化策略
算法·缓存·性能优化·gis·geoai-up
m0_6294947310 小时前
LeetCode 热题 100-----25.回文链表
数据结构·算法·leetcode·链表
ʚ希希ɞ ྀ11 小时前
单词拆分----dp
算法