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

问题描述:给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:字母异位词指字母相同,但排列不同的字符串。不考虑答案输出的顺序。

示例 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" 的字母异位词。

//思路一:固定该滑动窗口大小,逐步平移该窗口
class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<>();

        int l = 0;
        int r = p.length();
        //[l,r) 范围内字符,组成字符串

        while (r<=s.length()){
            String newP = s.substring(l,r);
            if(isAnagram(newP,p)){
                res.add(l);
            }
            l++;
            r++;
        }
        return res;
    }

   //判断两个字符串是否是Anagram
   //先判断长度是否相同,不相同,直接返回false
   //统计 s1字符串中每个小写字母出现的频率,根据s2是否出现相同的字母以及出现的字母的频率是否相同
    private boolean isAnagram(String word1,String word2){
        if(word1.length() != word2.length()){
            return false;
        }

        int[] freq = new int[26];

        for(int i=0;i<word1.length();i++){
            freq[word1.charAt(i)-'a']++;
        }

        for(int i=0;i<word2.length();i++){
            char c = word2.charAt(i);
            if(freq[c-'a']==0){
                // word1 不包括字符 c,但是 word2 包括,则 word1 和 word2 必然不是字母异位词
                return false;
            }
            freq[c-'a']--;
        }
        return true;
    }
}

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> ret = new ArrayList<>();
        if (s == null || s == "") {
            return ret;
        }
        //统计字符串p中出现的小写字符的频率
        int[] pFreq=new int[256];
        //count是p中的字符数
        int count=p.length();
    
        for(int i=0;i<count;i++){
            pFreq[p.charAt(i)]++;
        }
        int l=0,r=0;
        //[l,r)表示滑动窗口
        while(r<s.length()){
            if(pFreq[s.charAt(r++)]-->=1){
                //每次有一个p中字符进入窗口,扩展窗口,并且count–1
                count--;
            }
            if(count==0){
                //当count == 0的时候,表明我们的窗口中包含了p中的全部字符,得到一个结果。
                ret.add(l);
            }
    
            if (r-l == p.length()) {
                //当窗口包含一个结果以后,为了进一步遍历,我们需要缩小窗口使窗口不再包含全部的p,
                //同样,如果pFreq[char]>=0,表明一个在p中的字符就要从窗口移动到p字符串中,那么count ++
                if (pFreq[s.charAt(l++)]++ >= 0) {
                    count++;   // one more needed to match
                }
            }
        }
        return ret;
    }
}

参考:

posted @ 2024-02-04 23:04  行行行行星  阅读(23)  评论(0)    收藏  举报