字符串的最大、最小表示法

字符串的最大、最小表示法


前言

什么是字符串的最大、最小表示法?

对于一个字符串,求它的循环的同构字符串中字典序最大的就是最大表示法,同理字典序最小的就是最小表示法。

如:给定字符串为 s = b a c d s=bacd s=bacd,则最大表示法为 d b a c dbac dbac,最小表示法为 a c d b acdb acdb



求解字符串的的最小表示法

对于求最小表示法的实质就是找到一个位置,从这个位置开始的字符串的字典序最小,那么就可以利用指针来进行操作。

可以令 i = 0 i=0 i=0, j = 1 j=1 j=1来表示最小位置,同时来维护更新两个指针求解位置。

s [ i ] > s [ j ] s[i]>s[j] s[i]>s[j]时,i=j,j++

s [ i ] < s [ j ] s[i]<s[j] s[i]<s[j]时,j++

s [ i ] = s [ j ] s[i]=s[j] s[i]=s[j]时,添加一个新指针k,分别从 i + k i+k i+k j + k j+k j+k的位置进行比较,当 s [ i + k ] = s [ j + k ] s[i+k]=s[j+k] s[i+k]=s[j+k]时k++;当 s [ i + k ] > s [ j + k ] s[i+k]>s[j+k] s[i+k]>s[j+k] i = i + k + 1 i=i+k+1 i=i+k+1;当 s [ i + k ] < s [ j + k ] s[i+k]<s[j+k] s[i+k]<s[j+k] j = j + k + 1 j=j+k+1 j=j+k+1

在第三种情况中为什么要让 i = i + k + 1 i=i+k+1 i=i+k+1或者 j = j + k + 1 j=j+k+1 j=j+k+1呢?

因为当 s [ i + k ] < s [ j + k ] s[i+k]<s[j+k] s[i+k]<s[j+k]时,在s串中从j到j+k这个区间里的任意位置开始的串的字典序都是大于从i开始的字符串的,所以为了降低复杂度直接令 j = j + k + 1 j=j+k+1 j=j+k+1,同理 i = i + k + 1 i=i+k+1 i=i+k+1也是这个道理。

最大表示法的求解思路也类似。


模板
int Min_or_Max(int op,char *a)//op=0求最小表示法,op=1求最大表示法
{
    int i,j,k,t;
    i=0,j=1,k=0;
    while(i<len&&j<len&&k<len)
    {
        t=a[(i+k)%len]-a[(j+k)%len];
        if(!t) k++;
        else
        {
            if(op)
            {
               if(t>0) j+=(k+1);
               else i+=(k+1);
            }
            else
            {
                if(t>0) i+=(k+1);
                else j+=(k+1);
            }
            if(i==j) j++;
            k=0;
        }
    }
    return min(i,j)+1;
}

例题

hdu-3374

题意:

求最小、最大表示法的开始位置和出现的次数。


思路:

对于最小、最大表示法可直接套模板求即可。至于出现次数不就是就最小循环节,然后用长度除最小循环节就是出现次数了。


参考代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
char a[maxn];
int nex[maxn],len;
void getnext()
{
    for(int i=2,j=0;i<=len;i++)
    {
        while(j&&a[i]!=a[j+1])j=nex[j];
        if(a[i]==a[j+1])j++;
        nex[i]=j;
    }
}
int Min_or_Max(int op,char *a)
{
    int i,j,k,t;
    i=0,j=1,k=0;
    while(i<len&&j<len&&k<len)
    {
        t=a[(i+k)%len]-a[(j+k)%len];
        if(!t) k++;
        else
        {
            if(op)
            {
               if(t>0) j+=(k+1);
               else i+=(k+1);
            }
            else
            {
                if(t>0) i+=(k+1);
                else j+=(k+1);
            }
            if(i==j) j++;
            k=0;
        }
    }
    return min(i,j)+1;
}
int main()
{
    while(~scanf("%s",a+1))
    {
        len=strlen(a+1);
        int maxx=Min_or_Max(1,a+1);
        int minn=Min_or_Max(0,a+1);
        getnext();
        int ans=len-nex[len];
        if(ans!=len&&len%ans== 0)ans=len/ans;
		else ans=1;
        printf("%d %d %d %d\n",minn,ans,maxx,ans);
    }
    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值