广西大学东信杯 F.金手指
F金手指
最小字符串
- key:循环同构 ,最小字典序,
最小字典序的实现-----模式化
- 对比
- 拼接 -----发现一个新函数可用 s.substr();-----类似vb中的mid函数。
并且,对于string来说 可以直接进行< > =比较特别好用 拼接用+也方便!
关于k取值范围的问题:k<=n 最后一个位置,这里还有一个关键点,string分配是动态分配,所以即使是取到n的位置,也不会显示溢出。
当输入字符为aaaaaa时,此重复字符串,执行一次便跳出循环,此时k=n-1.
string minstring(string s){
int p1=0,p2=1,k; //开始的标记
int n=s.length(); //取长度
int site; //标记最小字典序开始的位置
while(p1<n&&p2<n){ //两个指针对应的位置都要不超过边界
k=0; //每次都是重新重头开始比较
while(k<=n&&s[p1+k]==s[p2+k]) k++;
if(s[p1+k]>s[p2+k]){
if(p1+k+1<=p2){ //注意这里是等号 因为即使相等 p1也要跑后面去不可能相同比较
p1=p2+1;
}else{
p1=p1+k+1;
}
}else if(s[p1+k]<s[p2+k]){
if(p2+k+1<=p1){
p2=p1+1;
}else{
p2=p2+k+1;
}
}
}
site=min(p1,p2);
return s.substr(site)+s.substr(0,site);
}
string minstring(string s){
int p0=0,p1=1,k;
int site,n=s.length();
while(p0<n&&p1<n){
k=0;
while(k<=n&&s[p0+k]==s[p1+k]) k++;
if(s[p0+k]>s[p1+k])
if(p0+k+1<=p1) p0=p1+1;
else p0=p0+k+1;
else if(s[p0+k]<s[p1+k])
if(p1+k+1<=p0) p1=p0+1;
else p1=p1+k+1;
}
return s.substr(min(p0,p1))+s.substr(0,min(p0,p1)-1);
//或者 先把min(p0,p1)放进site中
}
string minstring(string s)
{
int p0=0,p1=1;
int site,n=s.length();
while(p0<n&&p1<n)
{
while(k<n&&s[p0+k]==s[p1+k]) k++;
}
}
KMP----字符串模式匹配算法----关键字搜索
算法思想:模式串向右移动与主串进行比对,发现不同,为了节省时间,不直接将将模式串往后移一个位置,而是移动到在已匹配的字符中某个重复的最大字串位置
公式:T[i-ki-1]==P[0k-1]
遗留问题:取后面加前面为什么过不了 网上用的是两倍原字符串然后寻找关键字
巧妙:先找到每个位置的next(最大重复字符串指针的位置 便于副串的回溯)
有动态的思想了,顺着思路,若当前位置匹配,当然要匹配下一个位置了,下一个位置匹配,那么下一个位置的next应该和这个位置的next相同,若不匹配,就是目前的位置。若当前位置不匹配,那就从当前位置的上一个位置开始吧(上一个位置可能会经历过好几次不匹配,然后回到最初的起点。)。而k=-1就是为了如果回到最初开始服务的,并且最初的当前位置即j的next已经被赋值过了!可以看next[0]=-1。
这里k还有个很关键的点,在needle中表示的是位置信息,而赋值给next后表示的是与当前比较的j相同的位置的后一个位置!(即不匹配的第一个位置)
void getnext(string needle,int *next){
int next[0]=-1;//为什么为-1 首先
int k=-1;
int j=0;
while(j<needle.length()){
if(k==-1||needle[k]==needle[j]){
if(needle[++k]==needle[++j]){
next[j]=next[k];
}else{
next[j]=k;
}
}else{
k=next[k];
}
}
int KMP(string A,string B){//T是字串 P是副串 用于对比关键字
int pa=0,pb=0;
while(pa<A.length()&&pb<B.length()){
if(A[pa]==B[pb]){
pa++,pb++;
}else{
pb=next[pb];
}
}
//若为寻找关键字则
if(pb==B.length)
return pa-pb;//匹配开始的位置
else
return -1;
//若为对比两个长度相同的字符串 直接返回 1即可 然后进行判断
}
//输出
int KMP(string a,string b,int *next)
{
int pa=0,pb=0;
while(pa<a.length()&&pb<(int)b.length())//注意这里加"int"! 因为length()类型是unsigned int
{
if(pb==-1||a[pa]==b[pb])
{
pa++; //这里,匹配下一个位置(若pb=-1即匹配0和a的后一个位置,pb!=-1 即此位置相同,匹配下一个位置,没问题!)
pb++;
}else
{
pb=next[pb];
}
}
if(pb==b.length()){
return pa-pb;
}
else
{
return -1;
}
}
signed main()
{
string a,b;
cin>>a>>b;
int next[b.length()];
get_next(b,next);
cout<<next[0];
cout<<KMP(a,b,next);
}