算法题8:找到字符串中所有字母异位词
问题描述:
给定两个字符串 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" 的异位词。
思路:
滑动窗口:遍历s的多有长为n的子串s1,如果s1的每种字母的出现次数和p的每种字母的出现次数都相同,那么s1是 p 的异位词
维护长为 n 的子串 s1的每种字母的出现次数。如果 s1的每种字母的出现次数和 p 的每种字母的出现次数都相同,那么 s1是 p 的异位词,把 s1
左端点下标加入答案。
python:
使用python3中collections模块的Counter类,可以统计出字符串中每个字母的次数,
from collections import Counter class Solution: def findAnagrams(self, s: str, p: str) -> List[int]: res = [] cnt_p = Counter(p) # 统计p中每个字母出现次数如{"a":1, "b":1} cnt_s = Counter() # 统计S的长度为len(p)的子串y的每种字母出现次数 for right, i in enumerate(s): # right从0开始 cnt_s[i] += 1 # 右端点字母进入窗口 left = right -len(p) + 1 if left < 0: # 窗口长度不足len(p) continue if cnt_s == cnt_p: #子串y和p的每种字母出现次数相同 res.append(left) # y的左端点下标加入结果 cnt_s[s[left]] -= 1 #左端点字母离开窗口 return res
结果:

也可以用笨方法,通过列表切片的方式实现滑动窗口判断:
截取指定长度的字符串排序进行判断
class Solution: def findAnagrams(self, s: str, p: str) -> List[int]: n = len(s) step = len(p) res = [] p = sorted(p) for i in range(n): if sorted(s[i: i+step]) == p: res.append(i) return res
Java:
class Solution { public List<Integer> findAnagrams(String s, String p) { List<Integer> res = new ArrayList<>(); int[] cntP = new int[26]; // 统计p每种字母出现次数 int[] cntS = new int[26]; // 统计s的长度为p.length()的子串s1 for (char c : p.toCharArray()){ cntP[c - 'a']++; // 统计p的字母次数 } for (int right = 0; right < s.length(); right++){ cntS[s.charAt(right) - 'a']++; // 右端点字母进入窗口 int left = right - p.length() + 1; if (left < 0){ // 窗口长度不足p.length() continue; } if (Arrays.equals(cntS, cntP)) { // s1和p的每种字母的出现次数相同 res.add(left); // s1左端点下标加入答案 } cntS[s.charAt(left) - 'a']--; // 左端点字母离开窗口 } return res;
结果:


浙公网安备 33010602011771号