LeetCode——438. 找到字符串中所有字母异位词(数组、滑动窗口)

438. 找到字符串中所有字母异位词(数组、滑动窗口)

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目

给定一个字符串 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” 的字母异位词。

思路

还是有些晕乎,具体见大佬:
https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/solution/hua-dong-chuang-kou-tong-yong-si-xiang-jie-jue-zi-/

遍历子串p,记录各个字母出现的次数;遍历母串s,right先动,遇到和子串中相同的数组,那么就加大窗口,并记录该字符数量;当左右指针相聚子串长度时,要判断子串和母串对应相等的字符数量是不是相等;相等时说明母串中以left开始的串符合子串p排列,将左指针left加入结果数组res;否则就需要将窗口缩小,并且继续遍历

代码

C++版本

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        unordered_map<char, int> need, window;//需求和窗口键值对
        vector<int> res;
        for(char c : p){
            need[c]++;//记录子串中各个字符的个数
        }
        int left = 0, right = 0;
        int valid = 0; int s_len = s.size(); int p_len = p.size();
        while(right < s_len){//字符串s的右指针遍历
            char c = s[right];//c是将要移入窗口的字符
            right++;
            // 进行窗口内数据的一系列更新
            if(need.count(c)){//子串t中含有元素c,则更新窗口
                window[c]++;
                if(window[c] == need[c]){//如果窗口中c字符和子串t中相应字符相等
                    valid++;//标记字符c的数量,valid++    
                }
            }

            // 判断左侧窗口是否要收缩
            while (right - left >= p_len) {
                if(valid == need.size()){//如果窗口中元素和子串t中字符c相等,满足,将起始下标left加入res结果
                    res.push_back(left);

                }
                // d 是将移出窗口的字符
                char d = s[left];
                // 左移窗口
                left++;
                // 进行窗口内数据的一系列更新
                if(need.count(d)){//need数组不为空
                    if(window[d] == need[d]){
                        valid--;
                    }
                    window[d]--;//不相等说明不为子串排列,窗口-1
                }
            }
        }
        return res;
    }
};

/*

 滑动窗口算法框架C++版
void slidingWindow(string s, string t) {
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;
    
    int left = 0, right = 0;
    int valid = 0; 
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        //  debug 输出的位置 
        printf("window: [%d, %d)\n", left, right);
        
        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

*/

Java代码

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        //需求和窗口键值对
        HashMap<Character, Integer> need = new HashMap<>();
        HashMap<Character, Integer> window = new HashMap<>();
        List<Integer> res = new ArrayList<>();//存储结果
        
        for(Character c : p.toCharArray()){
            //当need集合中有这个c时,就使用这个0值;如果没有就使用默认值defaultValue。
            need.put(c, need.getOrDefault(c, 0) + 1);//记录子串中各个字符的个数
        }
        int left = 0, right = 0;
        int valid = 0; int s_len = s.length(); int p_len = p.length();
        while(right < s_len){//字符串s的右指针遍历
            char c = s.charAt(right);//c是将要移入窗口的字符
            right++;
            // 进行窗口内数据的一系列更新
            if( need.containsKey(c) ){//子串t中含有元素c,则更新窗口
                window.put( c, window.getOrDefault(c, 0) + 1 );
                if( (window.get(c)).equals(need.get(c)) ){//如果窗口中c字符和子串t中相应字符相等,此处如果用==判断太长时通不过
                    valid++;//标记字符c的数量,valid++    
                }
            }

            // 判断左侧窗口是否要收缩
            while (right - left >= p_len) {
                if(valid == need.size()){//如果窗口中元素和子串t中字符c相等,满足,将起始下标left加入res结果
                    res.add(left);

                }
                // d 是将移出窗口的字符
                char d = s.charAt(left);
                // 左移窗口
                left++;
                // 进行窗口内数据的一系列更新
                
                if( need.containsKey(d)){
                    if( (window.get(d)).equals(need.get(d)) ){
                        valid--;    
                    }
                    window.put(d, window.get(d) - 1);
                }
            }
            
        }
        return res;
    }
}



/*

 滑动窗口算法框架Java版
void slidingWindow(string s, string t) {
    HashMap<Character, Integer> need = new HashMap<>();
    HashMap<Character, Integer> window = new HashMap<>();
    List<Integer> res = new ArrayList<>();//存储结果
    
    for(Character c : p.toCharArray()){
        need.put(c, need.getOrDefault(c, 0) + 1);
    }
        
    int left = 0, right = 0;
    int valid = 0; int s_len = s.length(); int p_len = p.length();
    while (right < s_len) {
        // c 是将移入窗口的字符
        char c = s.charAt(right);
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        //  debug 输出的位置 
        printf("window: [%d, %d)\n", left, right);
        
        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s.charAt(left);
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

*/

猜你喜欢

转载自blog.csdn.net/qq_34767784/article/details/107149814
今日推荐