您的位置:首页 > 其它

String Problem - HDU 3374 (kmp+最大最小表示)

2015-08-19 15:36 393 查看
题目大意:有一个字符串长度为N的字符串,这个字符串可以扩展出N个字符串,并且按照顺序编号,比如串


SKYLONG



SKYLONG 1
KYLONGS 2
YLONGSK 3
LONGSKY 4
ONGSKYL 5
NGSKYLO 6
GSKYLON 7

下面这7个都是原串的扩展(循环位移),现在需要求出来字典序最小的和字典序最大的那个串的标号。

输出说明:最小字典序的编号,最小字典序个数,最大字典序编号,最大字典序个数。

分析:以前也遇到过类似的求最小字典序的问题,不过当时不会,今天研究了一下发现是有个方法来专门处理这种问题的,就是最大最小表示

,这种方法采用两个指针,表示两个串的开头,如果开头不同直接让字典序大的后移,如果开头相同那么就使用一个计数长度k来往后移动,知道发现s[i+k] != s[j+k] 当然如果k==N那么这两个串都是最小的字典序了,否则,就让值大的那个指针往后移动,直到有指针超过N为止。

下面是代码:

==========================================================================================================

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;

const int MAXN = 1e6+7;

char s[MAXN<<1], s1[MAXN];
int Next[MAXN];

void GetNext(char s[], int N)
{
int i=0, j=-1;
Next[0] = -1;

while(i < N)
{
if(j==-1 || s[i]==s[j])
Next[++i] = ++j;
else
j = Next[j];
}
}
int GetMin(char s[], int N)
{///求最小的字典序的开始
int i=0, j=1;

while(i<N && j<N)
{
int k = 0;

while(s[i+k] == s[j+k] && k<N)
k++;

if(k == N)break;

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

return min(i, j);
}
int GetMax(char s[], int N)
{///求最大的字典序的开始
int i=0, j=1;

while(i<N && j<N)
{
int k = 0;

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

if(k == N)break;

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

return min(i, j);
}

int main()
{
while(scanf("%s", s1) != EOF)
{
int N = strlen(s1);

strcpy(s, s1);
strcat(s, s1);

GetNext(s, N);
int circle = N-Next
, times=1;

if(N % circle == 0)
times = N / circle;

printf("%d %d %d %d\n", GetMin(s, N)+1, times, GetMax(s, N)+1, times);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: