算法题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;

 

结果:

 

posted @ 2025-05-08 08:37  夏晓旭  阅读(55)  评论(0)    收藏  举报