考研数据结构算法题6——查找专题
作者:
就是要AC
,
2021-04-30 09:28:24
,
所有人可见
,
阅读 284
六、查找
0x00 kmp字符串
给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模板串P在模式串S中多次作为子串出现。
求出模板串P在模式串S中所有出现的位置的起始下标。
输入样例:
3
aba(模板串P)
5
ababa(模式串S)
输出样例:
0 2(输出P在S中出现的起始下标)
#include<bits/stdc++.h>
using namespace std;
const int N = 10010, M = 100010;
char p[N], s[M];
int n,m;
int ne[N];//next数组 匹配失败时 模板串回退的位置
int main(){
cin>>n>>p+1>>m>>s+1;//让下标从1开始
for(int i = 2, j = 0; i <= n; i++){//求出next数组
while(j&&p[j+1]!=p[i]) j = ne[j];//匹配j+1和i,若当前不匹配时 回退寻找匹配的位置
if(p[j+1] == p[i]) j++;//匹配 往前移动
ne[i] = j;//如果起点就不匹配 就是零 否则 就是当前匹配了的长度
}
for(int i = 1, j = 0; i <= m; i++){//匹配过程
while(j&&p[j+1]!=s[i]) j = ne[j];
if(p[j+1]==s[i]) j++;
if(j==n){
cout<<i - n<<" ";//匹配成功 输出下标
j = ne[j];//为继续匹配,在成功为强行失败即可
}
}
return 0;
}
0x01最短回文串
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: "aacecaaa" 输出: "aaacecaaa"
示例 2:
输入: "abcd" 输出: "dcbabcd"
/*思路 如对于串 abcd 想要将其变为回文串
那么先把它逆序 然后放在前面 自然是回文了
abcd
dcba
dcbaabcd ->是回文
但是我们发现根本没必要放这么多在前面 因为abcd的前缀和dcab的后缀有重合(如a) 所以为了只添加最少 的字符,我们在前方只需要添加不重复的即可
abcd
dcba
dcbabcd ->依然是回文
//为了添加的最少 我们就需要找到dcba的后缀和abcd的前缀重合的部分,且让重合部分最大即可
//故而联想到kmp算法,它的next数组就是用来求一个串的前缀和后缀相同的长度的最大值
//所以拼接起字符串 abcddcba 但是我们所求的前缀是不能超过中点的,因此用一个特殊字符隔开
// 即为 abcd#dcba 这样在匹配前后缀时,相同长度就一定不会超过#号了
// 这样问题就转化为了 求abcd#dcba的next数组 知道该串的最长前后缀相同时的最大长度为1
a a 前后缀相同的最大长度
所以把后半部分除去重叠的部分拼接到前半部分即可
答案就是 dcbabcd
大功告成!
*/
string shortestPalindrome(string s) {
string revs = s;
int tn = s.size();//终点处,#前面的位置
reverse(revs.begin(),revs.end());
s = ' '+ s + '#' + revs;//让下标从1开始
int n = s.size()-1;//实际长度
vector<int> ne(n+1);//next数组
for(int i = 2, j = 0; i <= n; i++){//求next数组
while(j&&s[i]!=s[j+1]) j = ne[j];
if(s[i]==s[j+1]) j++;
ne[i] = j;
}
return s.substr(tn+2,tn-ne[n])+s.substr(1,tn);//后半部分除去重叠后缀+前半部分
}