首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

最小示意法

2013-10-08 
最小表示法“最小表示法”思想在字符串循环同构问题中的应用(摘自周源的ppt)前言:“最小表示法”比起动态规划、

最小表示法

“最小表示法”思想在字符串循环同构问题中的应用(摘自周源的ppt)

前言:

“最小表示法”比起动态规划、贪心等思想,在当今竞赛中似乎并不是很常见。但是在解决判断“同构”一类问题中却起着重要的作用。

本文即将讨论字符串中的同构问题,如何巧妙地运用最小表示法来解题呢,让我们继续一起思考吧。

到底什么是循环同构的字符串呢?

直接举个例子:

比如 str1 = "abdea"  而字符串str2是str1从第i(i>0)个开始将str1从i循环到末尾再从头开始循环到i,那么这两个字符串就是循环同构的.比如str2 = "deaab";

那么什么是字符串的最小表示呢?

比如上面那个str1,就是从str1的同构字符串中字典序最小的,那么str1的最小表示就是"aabde".

如何得到一个字符串的最小表示?

 

设函数M(s)返回值意义为:

从s的第M(s)个字符引起的s的一个循环表示是s的最小表示。

若有多个值,则返回最小的一个

比如M("bbbaab") =  4; 也就是最小表示为aabbbb,是从字符串"bbbaab"的第4个的字符开始的同构字符串。

现在换一种思路:

设有字符串s1,s2

设u=s1+s1(也就是将s1复制一份到s1后面),w=s2+s2并设指针i,j指向u,w第一个字符

最小示意法

如果s1和s2是循环同构的,那么当i,j分别指向M(s1),M(s2)时,一定可以得到u[i→i+|s1|-1]=w[j→j+|s2|-1],迅速输出正确解。

最小示意法

同样s1和s2循环同构时,当i,j分别满足

i≤M(s1),j≤M(s2)时,

两指针仍有机会达到i=M(s1),j=M(s2)这个状态。

问题转化成,两指针分别向后滑动比较,如果比较失败,如何正确的滑动指针,新指针i’,j’仍然满足

i’≤M(s1),j’≤M(s2)

设指针i,j分别向后滑动k个位置后比较失败(k≥0),即有

u[i+k]≠w[j+k]

设u[i+k]>w[j+k],同理可以讨论u[i+k]<w[j+k]的情况。

最小示意法

因为u[x]在u[i]后(x-i)个位置,

对应的可以找到在w[j]后(x-i)个位置的w[j+(x-i)],

同样对应的有u[x+1]和w[j+(x+1-i)],u[x+2]和w[j+(x+2)-i],

直到u[i+k-1]和w[j+k-1]。

它们都是相等的,

即有u[x→i+k-1]=w[j+(x-i)→j+k-1]。

最小示意法

很容易就得到u[x→i+k]>w[j+(x-i)→j+k]。

所以s1(x-1)不可能是s1的最小表示!

因此M(s1)>i+k,

指针i滑到u[i+k+1]处仍可以保证小于等于M(s1)!

最小示意法  

同理,当u[i+k]<w[j+k]的时候,可以将指针j滑到w[j+k+1]处!

也就是说,两指针向后滑动比较失败以后,

指向较大字符的指针向后滑动k+1个位置。

举例:

设s1=‘babba’,s2=‘bbaba’。(两个同构字符串)

u=s1+s1='babbababba'  w=s2+s2='bbababbaba'

初始化i=0,j=0,k=0;(i作为u的指针,j作为w的指针)              

比较失败时k=1 (u[i+k]!=w[j+k]

由于u[i+k]<w[j+k]  所以j=j+k+1;

j = 2 i不变(i=0); k=0

继续比较发现当k=0时u[i+k]>w[j+k],所以i=i+k+1;

i=1,j不变(j=2);k=0;

继续比较,发现当k=2时u[i+k]>w[j+k]所以i = i+k+1;

i =  4j不变(j=2)k=0;

继续比较,这个时候就找到了最小表示ababb

下面贴下模板
 

int getminsub(char *a){    int i=0,j=1,len=strlen(a),k=0; //取两个同构的字符串一个从下标0开始,一个从下标1开始    while(i<len&&j<len&&k<len) //这里并没有将字符串复制一份添加到后面    {        if(k==len) break; //说明找到了a的最小表示        if(i==j) j++;        int ni=i+k,nj = j+k;        if(ni>=len) ni-=len; //就是回到字符串的开始去        if(nj>=len) nj-=len;        if(a[ni]>a[nj])        {            i+=k+1;            k=0;        }        else if(a[ni]<a[nj])        {            j+=k+1;            k=0;        }        else k++;    }    return  i; //返回从第i个字符开始时a的最小表示}


 

 

 

    

 

热点排行