最小表示法

最小表示法:

定义:

就是一个字符串的最小表示形式

解决过程:

将原字符串 \(s\) 复制一遍放在串尾

s=s+s;

\(i=0\) 指向字符串头,\(j=i+1\)

int i=0,j=1,len=s.size()/2;

再设一个偏移量 \(k=0\) ,如果 \(s[i+k]==s[j+k]\)\(k++\)

int k=0;
while(s[i+k]==s[j+k]) k++;

不相等让大的加上 \(k+1\)

因为在 \([i/j,i/j+k]\) 间都有对应的另一个指针指向的字符串比它小,所以一定不是最小表示。

if(s[i+k]>s[j+k]) i=i+(k+1);
else j=j+k+1;

如果 \(k \geq len\) 则说明字符串每个位置由相同字母组成,应该是满足条件的最小表示,直接跳出,转移到求最小值。

if(k>=len) break;

如果 \(i=j\) 则其中一个加 \(1\) 即可,没有实际影响。

if(i==j) i++;

最后求最小值,返回在原串内比较小的坐标开头

return min(i,j);

时间复杂度为 \(O(n)\)

代码:

int get_min(string s){
    s=s+s;
    int i=0,j=1,len=s.size()/2;
    while(i<len && j<len){
        int k=0;
        while(s[i+k]==s[j+k]) k++;
        if(k>=len) break;
        if(s[i+k]>s[j+k]) i=i+k+1;
        else  j=j+k+1;
        if(i==j) i++;
    }
    return min(i,j);
}

例题:

P1709 [USACO5.5]隐藏口令Hidden Password

这题就是模板题,但是注意读入时,题目给的数据有换行!!!

#include<bits/stdc++.h>
using namespace std;
int n;
char s[10000005];
int minstring(){
    for(int i=0;i<n;i++) s[i+n]=s[i];
    int len=strlen(s)/2;
    int i=0,j=1;
    while(i<len&&j<len){
        int k=0;
        while(s[i+k]==s[j+k]) k++;
        if(k>=len) break;
        if(s[i+k]>s[j+k]) i=i+k+1;
        else j=j+k+1;
        if(i==j) j++;
    }
    return min(i,j);
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>s[i];
    int ans=minstring();
    cout<<ans<<endl;
    system("pause");
    return 0;
}
posted @ 2021-09-25 21:09  Evitagen  阅读(165)  评论(0编辑  收藏  举报