字符串最小表示法

模板:

int min_max_express(char *s,int len,bool flag){//最小表示法和最大表示法写到一块儿了 
    int i=0,j=1,k=0; 
    while(i<len&&j<len&&k<len){//一次就能够找着 
        int t=s[(j+k)%len]-s[(i+k)%len];//比较两个字符 
        if(t==0)k++;//相等,就后移比较下一个字符 
        else{
            if(flag){//最小表示法 
                if(t>0)j+=k+1; //+(k+1)相当于直接把相等的跳过 
                else i+=k+1;
            }else{//最大表示法 
                if(t<0) j+=k+1; 
                else i+=k+1;
            }
            if(i==j)j++;
            k=0; 
        } 
    }
    return min(i,j);
}
View Code

最小表示法的意思:

对于一个字符串S,求S的循环的同构字符串S’中字典序最小的一个。由于语言能力有限,还是用实际例子来解释比较容易:

 设S=bcad,且S’是S的循环同构的串。S’可以是bcad或者cadb,adbc,dbca。而且最小表示的S’是adbc。 对于字符串循环同构的最小表示法,其问题实质是求

S串的一个位置,从这个位置开始循环输出S,得到的S’字典序最小。

博客:

例题:hdu 3374

代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
const int max_=1e6+5;
char str[max_];
int nex[max_];
void getnext(int n)
{
  //  int n=strlen(str);
    int i=0,k=-1;
    nex[i]=-1;
    while(i<n)
    {
        while(k>-1&&str[i]!=str[k])
            k=nex[k];
        nex[++i]=++k;
    }
}
int solve(bool f)
{
    int i=0,j=1,k=0;
    int len=strlen(str);
    while(i<len&&j<len&&k<len)
    {
        int t=str[(j+k)%len]-str[(i+k)%len];
        if(t==0)
            k++;
        else
        {
           if(f)
            {//最小表示法
                if(t>0)j+=k+1; //+(k+1)相当于直接把相等的跳过
                else i+=k+1;
            }
           else
            {//最大表示法
                if(t<0) j+=k+1;
                else i+=k+1;
            }
            if(i==j)j++;
            k=0;
        }
    }
    return min(i,j);
}
int main()
{
    while(scanf("%s",str)!=EOF)
    {
        int len=strlen(str);
        getnext(len);
        int k=len-nex[len];
        int ans;
        int Min=solve(1);
        int Max=solve(0);
        if(len%k==0)
            ans=len/k;
        else
            ans=1;
        printf("%d %d %d %d
",Min+1,ans,Max+1,ans);
    }
}
View Code
原文地址:https://www.cnblogs.com/linhaitai/p/9917495.html