广西大学东信杯 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); 
} 
posted @ 2022-03-13 10:34  TimMCBen  阅读(54)  评论(0)    收藏  举报