leetcode 567. 字符串的排列(滑动窗口-java)

滑动窗口

字符串的排列

难度 -中等
leetcode567. 字符串的排列
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。

换句话说,s1 的排列之一是 s2 的 子串 。
示例 1:

输入:s1 = "ab" s2 = "eidbaooo"

输出:true

解释:s2 包含 s1 的排列之一 ("ba").
示例 2:

输入:s1= "ab" s2 = "eidboaoo"

输出:false
提示:

1 <= s1.length, s2.length <= 1e4

s1 和 s2 仅包含小写字母

滑动窗口

这种题目,是明显的滑动窗口算法,相当给你一个 S 和一个 T,请问你 S 中是否存在一个子串,包含 T 中所有字符且不包含其他字符。

题目要求 t 的排列之一是 s 的一个子串。而子串必须是连续的,所以要求的 s 子串的长度跟 t 长度必须相等。

那么我们有必要把 t 的每个排列都求出来吗?当然不用。如果字符串 a 是 b 的一个排列,那么当且仅当它们两者中的每个字符的个数都必须完全相等。

所以,根据上面两点分析,我们已经能确定这个题目可以使用 滑动窗口 + hash表 来解决。
我们使用一个长度和 t 长度相等的固定窗口大小的滑动窗口,在 s 上面从左向右滑动,判断 s 在滑动窗口内的每个字符出现的个数是否跟 t 每个字符出现次数完全相等。
我们定义 need是对 t 内字符出现的个数的统计,定义 wind是对 s 内字符出现的个数的统计。在窗口每次右移的时候,需要把右边新加入窗口的字符个数在 wind 中加 1,把左边移出窗口的字符的个数减 1。如果 need== wind,那么说明窗口内的子串是 t 的一个排列,返回 True;如果窗口已经把 s遍历完了仍然没有找到满足条件的排列,返回 False。

代码演示

java 复制代码
 public boolean checkInclusion(String t, String s) {
        int n = t.length(), m = s.length();
        if (n > m) {
            return false;
        }
        HashMap<Character, Integer> need = new HashMap<>();
        HashMap<Character, Integer> wind = new HashMap<>();
        for (char c : t.toCharArray()){
            need.put(c,need.getOrDefault(c,0) + 1);
        }
        int left = 0;
        int right  = 0;
        int valid = 0;
        while (right < m){
            //右指针 向右移动 窗口扩大
            char c = s.charAt(right);
            right++;
            //判断新进来的字符 是否是需要的。
            if (need.containsKey(c)){
                wind.put(c,wind.getOrDefault(c,0) + 1);
                if (wind.get(c).equals(need.get(c))){
                    valid++;
                }
            }
            //判断是否需要缩小窗口。
            while (right - left >= n){
                //找到直接返回true
                if (valid == need.size()){
                    return true;
                }
                //如何缩小窗口
                char d = s.charAt(left);
                left++;
                if (need.containsKey(d)){
                    if (need.get(d).equals(wind.get(d))){
                        valid--;
                    }
                    wind.put(d,wind.get(d) - 1);
                }
            }
        }
        return false;
    }

进阶优化版

这道题目中说明只有小写字母,因此我们可以用数组代替hash表,进行优化,数组代替hash表有两个好处,

1.优化了常数时间,数组的时间效率高于hash表,

2.优化了内存,数组更省空间,

代码演示:

java 复制代码
  public boolean checkInclusion(String t, String s) {
        int n = t.length(), m = s.length();
        if (n > m) {
            return false;
        }
        int[] need = new int[26];
        int[] wind = new int[26];
        for (char c : t.toCharArray()){
           ++need[c - 'a'];
        }
        int left = 0;
        int right  = 0;
        while (right < m){
            //右指针 向右移动 窗口扩大
            char c = s.charAt(right);
            right++;
            //判断新进来的字符 是否是需要的。
            if (need[c - 'a'] != 0){
                ++wind[c - 'a'];
            }
            //判断是否需要缩小窗口。
            while (right - left >= n){
                //找到直接返回true
                if (Arrays.equals(wind,need)){
                    return true;
                }
                //如何缩小窗口
                char d = s.charAt(left);
                left++;
                if (need[d - 'a'] != 0){
                    --wind[d - 'a'];
                }
            }
        }
        return false;
    }

上期经典

leetcode76. 最小覆盖子串

相关推荐
cc.ChenLy35 分钟前
算法从入门到精通实战指南
算法
Jerry7 小时前
LeetCode 160. 相交链表
算法
认真的酒窝7 小时前
自己动手开发编译器(十一)语义分析
java·开发语言
Lyn_Li7 小时前
扫描 PDF 歪了怎么办?用 6 种检测方法做本地批量扶正(附开源工具)
python·pdf·ocr·tesseract·开源工具·文档处理·本地处理·扫描件纠偏
Jerry8 小时前
LeetCode 19. 删除链表的倒数第 N 个结点
算法
金銀銅鐵8 小时前
费马小定理
python·数学·算法
wbs_scy9 小时前
Linux C++ 高并发编程:线程池全链路深度解析,从原理到手撕实现
java·开发语言
JAVA面经实录9179 小时前
Linux 常用命令完整知识体系
java·linux·开发语言·汇编
技术不好的崎鸣同学9 小时前
[ACTF2020 新生赛]Exec 思路及解法
算法·安全·web安全
Full Stack Developme10 小时前
Java LRU 与 LFU 算法及应用
java·开发语言·算法