力扣438:找到字符串中所有字母异位词

力扣438:找到字符串中所有字母异位词

题目描述

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

输入输出样例

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

Tips

  • 1 <= s.length, p.length <= 3 * 104
  • sp 仅包含小写字母

解法一:暴力解法


class Solution
{
public:
    vector<int>findAnagrams(string s,string p)
    {
        vector<int>res;
        if(s.empty()||p.empty())
        {
            return res;
        }

        int sLength=s.size();
        int pLength=p.size();

        unordered_map<char,int>maps;
        for(int i=0;i<pLength;i++)
        {
            maps[p[i]]++;
        }

        for(int i=0;i<=sLength-pLength;i++)
        {
            string tempStr=s.substr(i,pLength);
            if(defineStr(tempStr,maps))
            {
                res.push_back(i);
            }
        }
        return res;
    }

    bool defineStr(string str,unordered_map<char,int>maps)
    {
        for(int i=0;i<str.size();i++)
        {
            if(maps.count(str[i]))
            {
                maps[str[i]]--;
            }
        }

        //对最后得到的结果进行遍历
        for(auto i:maps)
        {
            if(i.second!=0)
            {
                return false;
            }
        }
        return true;
    }
};

容易超出编译时间

解法二:最优解:滑动窗口法

//面对字串问题时,一般可以采用使用滑动窗口进行求解
//滑动窗口需要明确考虑四个问题
//1.当移动right 扩大窗口,即加入字符的时候,应该考虑更新那些数据
//2.什么条件下,窗口应该暂停扩大,开始移动left缩小窗口
//3.当移动left缩小窗口,即移出字符时,应该更新那些数据
//4,我们要的结果应该在扩大窗口时还是在缩小窗口时更新

class Solution2
{
public:
    vector<int>findAnagrams(string s,string p)
    {
        //建立hash表,窗口,要查找的值

        unordered_map<char,int>windows,pMaps;

        //将原来的值赋给pMaps
        for(auto i:p)
        {
            pMaps[i]++;
        }
    
        //定义滑动窗口,验证的字符数
        int left=0,right=0;
        int valid=0;

        vector<int>res;
        //进入滑动窗口
        while(right<s.size())
        {
            char temp=s[right];
            right++;

            //回答第一个问题,当移动右指针需要在那些地方更新
            //如果该字符时所需的字符,边将其加入到窗口,并且如果窗口的该值数目与所需的该值数目相等,验证可直接进行+1
            if(pMaps.count(temp))
            {
                windows[temp]++;
                if(windows[temp]==pMaps[temp])
                {
                    valid++;
                }
            }

            //回答第二个问题,左侧窗口什么时候需要收缩
            //当左右滑动窗口的长度大于所需验证的字符的长度的时候便需要收缩
            while(right-left>=p.size())
            {
                //回答第四个问题,结果在缩小窗口时更新
                //当验证数目刚好与所需的字符数目相同时,将结果放入res数组中
                if(valid==pMaps.size())
                {
                    res.push_back(left);
                }

                char tempLeft=s[left];
                left++;
            
                //回答第三个问题,当进行窗口更新时,需要更新那些数据
                if(pMaps.count(tempLeft))
                {
                    if(windows[tempLeft]==pMaps[tempLeft])
                    {
                        valid--;
                    }
                    windows[tempLeft]--;
                }

            }
        }
        return res;

    }
};




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值