• LeetCode 438. 找到字符串中所有字母异位词


    传送门

    Solution

    思路1:

    滑动窗口。维护窗口内字符的数量,判断与\(p\)字符串数量是否相等。复杂度\(O((sLen-pLen)*26)\)

    class Solution {
        public List<Integer> findAnagrams(String s, String p) {
            int sLen = s.length(), pLen = p.length();
            if (sLen < pLen) {
                return new ArrayList<>();
            }
            List<Integer> ans = new ArrayList<>();
            int[] sCount = new int[26];
            int[] pCount = new int[26];
            for (int i = 0; i < pLen; i++) {
                pCount[p.charAt(i) - 'a']++;
                sCount[s.charAt(i) - 'a']++;
            }
            if (Arrays.equals(sCount, pCount)) {
                ans.add(0);
            }
            for (int i = 0; i < sLen - pLen; i++) {
                sCount[s.charAt(i) - 'a']--;
                sCount[s.charAt(i + pLen) - 'a']++;
                if (Arrays.equals(sCount, pCount)) {
                    ans.add(i + 1);
                }
            }
            return ans;
        }
    }
    

    思路2:

    滑动窗口优化。不维护窗口与\(p\)字符串字符的数量,维护他们的差值\(diff\)\(diff\)\(0\),即为异位词。判断左边界和右边界对\(diff\)的贡献。

    左边界考虑\(1\)\(0\)

    • 若为\(1\),滑动后\(diff+1\)
    • 若为0,滑动后\(diff-1\)

    右边界考虑\(-1\)\(0\)

    • 若为\(-1\),滑动后\(diff+1\)
    • 若为0,滑动后\(diff-1\)
    class Solution {
        public List<Integer> findAnagrams(String s, String p) {
            int sLen = s.length(), pLen = p.length();
            if (sLen < pLen) {
                return new ArrayList<>();
            }
            List<Integer> ans = new ArrayList<>();
            int[] count = new int[26];
            for (int i = 0; i < pLen; i++) {
                count[p.charAt(i) - 'a']--;
                count[s.charAt(i) - 'a']++;
            }
            int diff = 0;
            for (int i = 0; i < 26; i++) {
                if (count[i] != 0) {
                    diff++;
                }
            }
            if (diff == 0) 
                ans.add(0);
            for (int i = 0; i < sLen - pLen; i++) {
               if (count[s.charAt(i) - 'a'] == 1) {
                   diff--;
               } else if (count[s.charAt(i) - 'a'] == 0) {
                   diff++;
               }
               count[s.charAt(i) - 'a']--;
               if (count[s.charAt(i + pLen) - 'a'] == -1) {
                   diff--;
               } else if (count[s.charAt(i + pLen) - 'a'] == 0) {
                   diff++;
               }
               count[s.charAt(i + pLen) - 'a']++;
               if (diff == 0) {
                   ans.add(i + 1);
               }
            }
            return ans;
        }
    }
    

    思路3:

    滑动窗口+双指针。如果\(s\)的某个字符多了,肯定就不符合,所以只能通过不停弹出\(l\)来符合;只有字符不超过\(p\)的字符数量且长度与\(p\)一致,才为答案。

    class Solution {
        public List<Integer> findAnagrams(String s, String p) {
            int sLen = s.length(), pLen = p.length();
            if (sLen < pLen) {
                return new ArrayList<>();
            }
            List<Integer> ans = new ArrayList<>();
            int[] sCount = new int[26];
            int[] pCount = new int[26];
            for (int i = 0; i < pLen; i++) {
                pCount[p.charAt(i) - 'a']++;
            }
            int l = 0;
            for (int r = 0; r < sLen; r++) {
                int right = s.charAt(r) - 'a';
                sCount[right]++;
                while (sCount[right] > pCount[right]) {
                    int left = s.charAt(l) - 'a';
                    sCount[left]--;
                    l++;
                }
                if (r - l + 1 == pLen) {
                    ans.add(l);
                }
            }
            return ans;
        }
    }
    

    思路4:

    \(p\)看做资源去消耗,能不能把当前\(s\)吃掉,吃掉后\(r++\),有可能长度与\(pLen\)一致,如果吃不掉当前\(s\),那就收回之前的\(l++\),如果出现未出现的字符,加上后也会消耗掉。

    class Solution {
        public List<Integer> findAnagrams(String s, String p) {
            int sLen = s.length(), pLen = p.length();
            List<Integer> ans = new ArrayList<>();
            int[] count = new int[26];
            for (int i = 0; i < pLen; i++) {
                count[p.charAt(i) - 'a']++;
            }
            int l = 0, r = 0;
            while (r < sLen) {
                if (count[s.charAt(r) - 'a'] > 0) {
                    count[s.charAt(r++) - 'a']--;
                    if (r - l == pLen) 
                        ans.add(l);
                } else {
                    count[s.charAt(l++) - 'a']++;
                }
            }
            return ans;
        }
    }
    
    埋骨何须桑梓地,人生无处不青山
  • 相关阅读:
    118. Pascal's Triangle
    697. Degree of an Array
    1013. Partition Array Into Three Parts With Equal Sum
    167. Two Sum II
    ol7 禁用mysql 自启动
    pgsql常用命令
    清空history 命令记录
    pgsql启动报错
    在rhel 7.4中安装glibc-devel-2.17-196.el7.i686包的过程详录
    postgresql-9.2 install
  • 原文地址:https://www.cnblogs.com/ACMerszl/p/15622326.html
Copyright © 2020-2023  润新知