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

题目大意:有一个字符串长度为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[N], 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;
}

 

 

 

 

posted @ 2015-08-19 15:36  无忧望月  阅读(376)  评论(0编辑  收藏  举报
levels of contents