Leetcode 438. 找到字符串中所有字母异位词 (中等)双指针(滑动窗口)

题目描述:

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

来源:力扣(LeetCode)
 

思路:

滑动窗口算法的思路是这样:(摘自 labudadong 公众号)

1、我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个「窗口」。

2、我们先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的字符串符合要求(包含了p 中的所有字符)。

3、此时,我们停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的字符串不再符合要求(不包含p 中的所有字符了)。同时,每次增加 left,我们都要更新一轮结果。

4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。

本题中,我们需要在第3步开始对此时窗口的长度进行计算,看是否与p的长度相等(即异位词)。

//双指针————滑动窗口

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> res;
        unordered_map<char,int> window;
        unordered_map<char,int> target;

        int left = 0;
        int right = 0;
        int match_cnt = 0;

        for(char c : p)//记录 p中各个字符的出现次数
            target[c]++;
        
        while(right < s.size())//当right走到最后时,循环结束
        {
            char c1 = s[right];
            if(target.count(c1))
            {
                window[c1]++;
                if(window[c1] == target[c1])
                    ++match_cnt;
            }
            ++right;

            while(match_cnt == target.size())//此时窗口中的字符满足p中的要求
            {
                if(right-left == p.size()){
                    res.push_back(left);
                }

                char c2 = s[left];
                if(target.count(c2))
                {
                    window[c2]--;
                    if(window[c2] < target[c2])
                        --match_cnt;
                }
                ++left;
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值