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

发布时间 2023-08-24 16:40:14作者: 摆烂卧底

1.问题描述

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

2.说明

字母异位词指字母相同,但排列不同的字符串。

输入:

输入两个字符串s和p,只包含小写英文字母,长度都不超过 20100

输出:

输出一系列整数,为子串的起始索引,按照由小到大的顺序输出,整数之间以空格分隔。

如果起始索引集合为空,则输出“none”,不包括引号。

3.范例:

输入:

cbaebabacd
abc

输出:

0 6

4.思路

方法1:移动窗口子串

len定义为p字符串长度,遍历s字符串,每次取长度从 i 开始,长度为len的字符串给word,并对word和p字符串进行排序,已进行判断是否相同,相同则将 i 存入结果。

方法2:双指针

head指针,指向异位词子串头元素,初始值0;

tail指针,指向异位词子串未元素的下一个元素位置,初始值为0;

chars[128]数组,记录p字符串的每个字符数,初始值为0.

遍历s字符串,判断是否符合异位词子串了。具体逻辑如下所示:   

【逻辑1】如果tail指针指向的字符,在chars中对应的值大于0,则执行减1操作,并且执行tail++;   

【逻辑2】否则,获得head指针指向的字符,然后针对该字符在chars数组中的位置处执行加1操作,并且执行head++;   

【逻辑3】当满足逻辑1的情况下,我们判断如果tail减去head等于p的长度,那么就说明我们找到了p的异位词子串,则将head复制给结果List即可。

思路参考:https://zhuanlan.zhihu.com/p/626490026

注意!!!输出要求,整数之间使用空格隔开,但输出最后一个索引时,不需要空格!!!

5.代码

方法1:移动窗口子串--缺点,运行速度慢

#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
public:
    vector<int> findAnagrams(string s,string p)
    {
        vector<int> res;
        string word="";
        int len=p.length();
        for(int i=0;i<s.length();i++)
        {
            word=s.substr(i,len);
            sort(p.begin(),p.end());
            sort(word.begin(),word.end());
            if(p==word)
            {
                res.push_back(i);
            }
        }
        return res;
    }
};
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    string s,p;
    cin>>s>>p;
    vector<int> res=Solution().findAnagrams(s,p);
    if(res.size()==0)
        cout<<"none";
    else
     for(int i=0;i<res.size();i++)
      {
        cout<<res[i];
        if(i!=res.size()-1)
          cout<<" ";
      }
return 0; }

 方法2:双指针,哈希表

#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
public:
    //双指针,哈希表
    vector<int> findAnagrams(string s,string p)
    {
        vector<int> res;
        int head=0;//指向异位词子串头元素
        int tail=0;//指向异位词子串未元素的下一个元素位置
        int chars[128]={0};//记录p字符串的每个字符数
        for(int i=0;i<p.length();i++)
        {
            chars[p[i]]++;
        }
        while(tail<s.length())
        {
            if(chars[s[tail]]>0)
            {
                chars[s[tail++]]--;
                if((tail-head)==p.length())
                    res.push_back(head);
            }
            else
                chars[s[head++]]++;
        }
        return res;
    }
};
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    string s,p;
    cin>>s>>p;
    vector<int> res=Solution().findAnagrams(s,p);
    if(res.size()==0)
        cout<<"none";
    else
        for(int i=0;i<res.size();i++)
        {
            cout<<res[i];
            if(i!=res.size()-1)
                cout<<" ";//注意输出要求,在输出最后一个索引时,不需要使用空格分隔
        }
    return 0;
}