第三周训练总结

一、KMP+最大最小值表示法

最大最小值表示法

最大最小表示法用于解决字符串的同构问题,其在复杂度为$ O(n) $的时间内求出一个字符串的所有同构串中字典序最大(小)的串的起始位置。

应用:

  • 给出$ n $个循环字符串判断有多少不同字符串:逐个用最大(小)表示法表示,然后加入 (Set) 去重
  • 循环字符串所有同构串中字典序最大(小)的表示:用最大(小)表示法求出起始位置,输出即可
  • 判断两个字符串是否同构:将两字符串用最大(小)表示法表示,然后逐个字符比较

原理:

设一字符串 (S),且 $S’ (是) S $的循环同构的串的最小表示,那么对于字符串循环同构的最小表示法,其问题实质是求 S 串的一个位置,从这个位置开始循环输出 (S),得到的 $S’ $字典序最小。

最朴素的算法是设$ i(、)j (两个指针,)i (指向最小表示的位置,)j $作为比较指针。

(i=0)(j=1),那么:

  • (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[i]=S[j] (时,)i $的指针移动的太少了,在遇到像 $bbb…bbbbbba $这样复杂的字符串时,时间复杂度可能会退化到 (O(n^2)),针对这一问题加以改进可得到 (O(n)) 的最小表示法的算法,其核心思路是在$ S[i]=S[j]$ 时同时维护 (i)、$j $两个指针

同样令 (i=0)(j=1),那么:

  • (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=i+k)
  • 否则 (j++)

最后返回$ i $和 $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
",minn+1,num,maxx+1,num);
    }
    return 0;
}

二、

原文地址:https://www.cnblogs.com/trirabbits/p/11514631.html