题目描述
给定两个字符串str和match,长度分别为N和M。实现一个算法,如果字符串str中含有子串match,则返回match在str中的开始位置,不含有则返回-1
若出现了多次,则按照升序输出所有出现位置
[要求]
时间复杂度为O(n)O(n)
输入描述:
第一行一个字符串str
第二行一个字符串match
输出描述:
输出若干个数,分别为match在str中出现的位置,从0开始标号。
若不存在输出-1
代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//获取next数组
vector<int> GetNext(string& match)
{
vector<int> next(match.size() + 1,0);
//设为-1是为了标记匹配到头了,如果为0可能会导致死循环
next[0] = -1;
//从第二个开始
int i = 2;
//用来找公共前后缀的指针
int k = 0;
while(i < match.size())
{
//如果出现相等,代表出现一个相同的前缀
if(match[i - 1] == match[k])
{
//保存
next[i] = k + 1;
//更新k的下标
k = next[i];
i++;
}
//等于-1代表匹配到头,需要重新开始匹配
else if(k == -1)
{
next[i] = 0;
i++;
}
//否则不为-1代表之前还有匹配,继续往前找
else
{
k = next[k];
}
}
return next;
}
int main()
{
string str;
string match;
while(getline(cin,str))
{
getline(cin,match);
//获取next数组
vector<int> next = GetNext(match);
//用来标记是否出现过匹配的情况,题意需要输出-1
int flag = 1;
//双指针
int i = 0;
int j = 0;
//开始循环
while(i < str.size())
{
//如果两个位置的字符相等直接++,判断是否匹配完成即可
if(str[i] == match[j])
{
i++;
j++;
if(j == match.size())
{
flag = 0;
cout<<i - match.size()<<" ";
j = next[j];
}
}
//代表两个位子的字符不想等,kmp就是为了不回溯i而回朔j的
else
{
//j回溯到有相同前后缀的位子
j = next[j];
if(j == -1)
{
j = 0;
i++;
}
}
}
if(flag)
cout<<-1<<endl;
}
return 0;
}
京公网安备 11010502036488号