• LeetCode438:找到字符串中所有字母异位词


    要求

    给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
    异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
    在这里插入图片描述

    思路

    方法一:滑动窗口 + 双指针
    用双指针来表示滑动窗口的两侧边界,当滑动窗口的长度等于p的长度时,表示找到一个异位词

    定义滑动窗口的左右两个指针left,right;表示滑动窗口在字符串s中的索引,
    right一步一步向右走遍历s字符串
    right当前遍历到的字符加入s_cnt后不满足p_cnt的字符数量要求,将滑动窗口左侧字符不断弹出,也就是left不断右移,直到符合要求为止。
    当滑动窗口的长度等于p的长度时,这时的s子字符串就是p的异位词。

    curLeft和curRight表示字符串s中索引为left和right的字符在数组中的索引

    public class LeetCode438 {
        public List<Integer> findAnagrams(String s, String p) {
            List<Integer> res = new ArrayList<>();
            if (s.length() < p.length()){
                return res;
            }
            //初始化空间
            int[] sCount = new int[26];
            int[] pCount = new int[26];
            //遍历p,把目标p中子串加入到pCount数组中
            for (int i = 0; i < p.length(); i++) {
                pCount[p.charAt(i) - 'a']++;
            }
            //left,right表示滑动窗口在字符串s中的索引下标
            int left = 0;
            for (int right = 0; right < s.length(); right++) {
                //获取字符串s中索引为right的字符在数组中的索引下标
                int curRight = s.charAt(right) - 'a';
                sCount[curRight]++;
                //左指针右移,缩小窗口
                while (sCount[curRight] > pCount[curRight]){
                    int curLeft = s.charAt(left) - 'a';
                    sCount[curLeft]--;
                    left++;
                }
                //如果滑动窗口的长度和p的长度相等,则添加起始索引下标
                if (right - left + 1 == p.length()){
                    res.add(left);
                }
            }
            return res;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34


    方法二:滑动窗口 + 窗口

    因为字符串中的字符全是小写字母,可以用长度为26的数组记录字母出现的次数
    设n = len(s), m = len§。记录p字符串的字母频次p_cnt,和s字符串前m个字母频次s_cnt
    若p_cnt和s_cnt相等,则找到第一个异位词索引 0
    继续遍历s字符串索引为[m, n)的字母,在s_cnt中每次增加一个新字母,去除一个旧字母
    判断p_cnt和s_cnt是否相等,相等则在返回值res中新增异位词索引 i - m + 1

    public List<Integer> findAnagrams(String s, String p) {
        int n = s.length(), m = p.length();
        List<Integer> res = new ArrayList<>();
        if(n < m) return res;
        int[] pCnt = new int[26];
        int[] sCnt = new int[26];
        for(int i = 0; i < m; i++){
            pCnt[p.charAt(i) - 'a']++;
            sCnt[s.charAt(i) - 'a']++;
        }
        if(Arrays.equals(sCnt, pCnt)){
            res.add(0);
        }
        for(int i = m; i < n; i++){
            sCnt[s.charAt(i - m) - 'a']--;
            sCnt[s.charAt(i) - 'a']++;
            if(Arrays.equals(sCnt, pCnt)){
                res.add(i - m + 1);
            }
        }
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    时间复杂度:O(n),for循环有O(n),数组的长度是常数,所以数组的比较也是常数级别的,那最终的时间复杂度就是O(n)
    空间复杂度:O(1),需要常数级别的额外空间

  • 相关阅读:
    等保测评结论为差,是不是表示等保工作白做了?
    memcpy和memmove的模拟实现,思路详解+代码实现
    C++数据存储、表示形式和基本运算
    深入理解Java虚拟机(第3版)学习笔记——Tomcat与OSGI中的类加载机制
    SpringBoot2.x整合Prometheus+Grafana【附源码+视频】
    从零开始配置深度学习环境:CUDA+Anaconda+Pytorch+TensorFlow
    IPV4地址概述
    分页和排序
    【security】spring security放行不生效,security放行后还是被拦截,路径变成了error
    户外花园藤条吊椅出口欧盟CE认证范围
  • 原文地址:https://blog.csdn.net/weixin_46426906/article/details/127609123