By Long Luo
Leetcode 438. 找到字符串中所有字母异位词 题目如下: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 438. 找到字符串中所有字母异位词 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。 示例 1: 输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。 示例 2: 输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。 提示: 1 <= s.length, p.length <= 3 * 10^4 s 和 p 仅包含小写字母
看到这道题,首先想到方法就是:
统计字符串 \(\textit{p}\) 字母及其数量; 使用双指针 + 滑动窗口 ,如果当前窗口的不同字母种类及其数量和字符串 \(\textit{p}\) 字符串一致,将当前下标增加为答案; 扫描到字符串 \(\textit{s}\) 结束。 方法一:HashMap + 滑动窗口 思路与算法:
使用 \(\texttt{HashMap}\) 存储字符串 \(\textit{p}\) 的不同字母种类及其数量。
在字符串 \(\textit{s}\) 中构造一个长度为与字符串 \(\textit{p}\) 的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量;当窗口中每种字母的数量与字符串 \(\textit{p}\) 中每种字母的数量相同时,则说明当前窗口为字符串 \(\textit{p}\) 的异位词。
代码如下所示: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 35 36 37 38 39 40 41 42 43 44 45 46 public List<Integer> findAnagrams (String s, String p) { List<Integer> ans = new ArrayList <>(); int pLen = p.length(); int sLen = s.length(); if (pLen > sLen) { return ans; } Map<Character, Integer> patMap = new HashMap <>(); for (char ch : p.toCharArray()) { patMap.put(ch, patMap.getOrDefault(ch, 0 ) + 1 ); } int left = 0 ; int right = left + pLen; Map<Character, Integer> winMap = new HashMap <>(); for (int i = left; i < right; i++) { char ch = s.charAt(i); winMap.put(ch, winMap.getOrDefault(ch, 0 ) + 1 ); } if (patMap.equals(winMap)) { ans.add(left); } while (right < sLen) { char chLeft = s.charAt(left); winMap.put(chLeft, winMap.get(chLeft) - 1 ); if (winMap.get(chLeft) == 0 ) { winMap.remove(chLeft); } char chRight = s.charAt(right); winMap.put(chRight, winMap.getOrDefault(chRight, 0 ) + 1 ); left++; right++; if (patMap.equals(winMap)) { ans.add(left); } } return ans; }
复杂度分析: 时间复杂度:\(O(m+(n-m) \times \Sigma)\) ,其中 \(n\) 为字符串 \(\textit{s}\) 的长度,\(m\) 为字符串 \(\textit{p}\) 的长度,\(\Sigma\) 为所有可能的字符数。需要 \(O(m)\) 来统计字符串 \(\textit{p}\) 中每种字母的数量;需要 \(O(m)\) 来初始化滑动窗口;需要判断 \(n-m+1\) 个滑动窗口中每种字母的数量是否与字符串 \(\textit{p}\) 中每种字母的数量相同,每次判断需要 \(O(\Sigma)\) 。因为 \(\textit{s}\) 和 \(\textit{p}\) 仅包含小写字母,所以 \(\Sigma=26=26\) 。
空间复杂度:\(O(\Sigma)\) 。用于存储字符串 \(\textit{p}\) 和滑动窗口中每种字母的数量。