、KMP +の最大値と最小値の表記
最大値と最小値の表現
複雑さは、同形のすべての文字列の(N)$ O $直列ストリング辞書的最大値(最小値)で決定したである最大最小表現同型文字列を解決するための開始時刻場所。
アプリケーション:
- 次に、最大値(最小値)と表記一つずつ追加:$ $ Nサイクルが与えられた文字列がどのように多くの異なる文字列が決定される\(セット\)重複排除を
- 全て同形ストリングループ文字列辞書最大値(最小値)を表しては:最大(最小)メソッドを出力する、開始位置を取得表します
- 方法によって表される2つの最大値(最小値)の文字列表現、および次いでによる文字の比較:同形二つの文字列かどうかを決定します
原理:
文字列の設定\(S \)を、そして$ S ' \(\)最小$ S同型巡回文字列、文字列Sを求めている本当の問題である最小サイクル同型表記のため、その後の文字列を言いました位置、サイクルを開始するには、この位置からの出力\(S \)は、最小の$辞書的に$ S」を得ました。
最も簡単な方法は私に$設定する(\ \) J \(二つのポインタ、\)私は\(極小点の指示位置、\)比較としてJ $ポインタ。
注文\(= 0私は\)、\ (1 J = \。) 、そして:
- 若\(S [i]が> S [J] \) 、则:\(I = Jの\) 、\(J = I + 1 \)
- もし\(S [I] <S [J] \) 、そして:\(J ++ \)
- 場合は\(S [I] =のS [J] \) 、その後、ポインタましょう\(K \) 、それぞれ、および$から$ I $ J \は、(位置を下に比較するまで\) S [I]!= S [ J] $
- 若\(S [I + K]> S [J + K] \) 、则:\(I = Jの\) 、\(J = I + 1 \)
- それ以外の場合は、$ jの++ $
最後に、私は$ $戻ります
[I] =のS [J]見ることができ、簡単なアルゴリズムのS $のよう\(、\)私はポインタが$ BBB ... bbbbbba $文字列などの複雑な、時間などの顔に、あまりにも少し動きます$複雑さがために低下することがある(\ O(^ N-2))\、改善すべき問題について得られた(\ O(N))\アルゴリズムは、その核となるアイデアは、$ Sでの最小の表現である[I] =を維持しながら、S [j]は$ (私は\)\、二つのポインタ$ $ J
同様にオーダー\(= 0 Iは\)、\ (1 J = \。) 、その後:
- 若\(S [i]が> S [J] \) 、则:\(I = Jの\) 、\(J = I + 1 \)
- もし\(S [I] <S [J] \) 、そして:\(J ++ \)
- S $ [I] =のS [J]の場合、\(、その後、ポインタ\を聞かせて) K (\から、それぞれ、)\は、私が(\と)\ダウンJ $の位置比較まで\(S [i]は!= S [J] \)
- 若\(S [I + K]> S [J + K] \) 、则:\(I = I + K \)
- それ以外の場合は\(J ++ \)
最後に、することができます私の$ $戻って、$ jは$小さな人
1、最小値表記
int minmumRepresentation(char *str) //最小表示法
{
int len=strlen(str);
int i=0; //指向字符串最小的位置
int j=1; //比较指针
int k=0; //str[i]与str[j]相等时一次移动几个
while(i<len&&j<len&&k<len)
{
int temp=str[(i+k)%len]-str[(j+k)%len];//比较值的长度
if(temp==0)
k++;
else
{
if(temp>0) //维护i
i=i+k+1;
else //维护j
j=j+k+1;
if(i==j) //相等时比较指针后移
j++;
k=0;
}
}
return i<j?i:j; //返回i、j中较小的那个
}
2、最大値表記
int maxmumRepresentation(char *str) //最大表示法
{
int len=strlen(str);
int i=0; //指向字符串最小的位置
int j=1; //比较指针
int k=0; //str[i]与str[j]相等时一次移动几个
while(i<len&&j<len&&k<len)
{
int temp=str[(i+k)%len]-str[(j+k)%len];//比较值的长度
if(temp==0)
k++;
else
{
if(temp>0) //维护i
j=j+k+1;
else //维护j
i=i+k+1;
if(i==j) //相等时比较指针后移
j++;
k=0;
}
}
return i<j?i:j; //返回两者最小值
}
HDU-3374の問題解決のアイデア
まず、サイクルは、最小および最大の表記表記が最小に対応する位置を特定するために、文字列であるかどうかが決定される、そのような表現は、文字の開始を見つけるために、文字列のループを識別することができ、その後、文字列辞書最小
コード:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define PI acos(-1.0)
#define E 1e-9
#define INF 0x3f3f3f3f
#define LL long long
const int MOD=10007;
const int N=1000000+5;
const int dx[]= {-1,1,0,0};
const int dy[]= {0,0,-1,1};
using namespace std;
int Next[N];
char str[N];
void getNext(char p[])
{
Next[0]=-1;
int len=strlen(p);
int j=0;
int k=-1;
while(j<len)
{
if(k==-1||p[j]==p[k])
{
k++;
j++;
Next[j]=k;
}
else
{
k=Next[k];
}
}
}
int minmumRepresentation(char *str) //最小表示法
{
int len=strlen(str);
int i=0;
int j=1;
int k=0;
while(i<len&&j<len&&k<len)
{
int temp=str[(i+k)%len]-str[(j+k)%len];
if(temp==0)
k++;
else
{
if(temp>0)
i=i+k+1;
else
j=j+k+1;
if(i==j)
j++;
k=0;
}
}
return i<j?i:j;
}
int maxmumRepresentation(char *str) //最大表示法
{
int len=strlen(str);
int i=0;
int j=1;
int k=0;
while(i<len&&j<len&&k<len)
{
int temp=str[(i+k)%len]-str[(j+k)%len];
if(temp==0)
k++;
else
{
if(temp>0)
j=j+k+1;
else
i=i+k+1;
if(i==j)
j++;
k=0;
}
}
return i<j?i:j;
}
int main()
{
while(scanf("%s",str)!=EOF)
{
getNext(str);
int n=strlen(str);
int len=n-Next[n];
int num=1;//数量
if(n%len==0)
num=n/len;
int minn=minmumRepresentation(str);//最小表示
int maxx=maxmumRepresentation(str);//最大表示
printf("%d %d %d %d\n",minn+1,num,maxx+1,num);
}
return 0;
}