最小表示法
来源:互联网 发布:linux ftp用户及目录 编辑:程序博客网 时间:2024/06/06 00:58
http://blog.csdn.net/runninghui/article/details/11694089
“最小表示法”思想在字符串循环同构问题中的应用(摘自周源的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
下面是自己的理解:
把一个长为len的字符串围成一个圈,然后以任意一个字符作为起点,都会产生一个新的长为len的字符串,字符串的最小表示就是所有新字符串中字典序最小的那个。其返回值为字典序最小的串的在原串中的起始位置。基本想法就是两个位置的字符比较,如果s[i+k] > s[j+k]那么i到i+k位置都不是最小表示的位置,所以i直接跳k+1步,反之j直接跳k+1步。
改进的代码:
Code:
int min_sub(string str){ int i = 0, j = 1, k = 0, len = str.length();//取两个同构的字符串一个从下标0开始,一个从下标1开始 while(i<len && j<len && k<len)//这里并没有将字符串复制一份添加到后面 { if(k == len) break;//说明找到了a的最小表示 if(i==j) j++; int p1=i+k>=len?i+k-len:i+k;//就是回到字符串的开始去 int p2=j+k>=len?j+k-len:j+k; if(str[p1] > str[p2]) i+=k+1,k = 0;//大于的话,str[i]为首的肯定不是最小表示,最大表示就改< if(str[p2] > str[p1]) j+=k+1,k = 0;//小于的话,str[i]为首的肯定不是最小表示,最大表示就改> if(str[p1] == str[p2]) k++;//相等的话,检测长度加1 } return i;//返回从第i个字符开始时str的最小表示}
- 最小表示法
- poj1509(最小表示法)
- hdu4162(最小表示法)
- 最小表示法
- 最小表示法
- 最小表示法
- 最小表示法模板
- 最小表示法
- 最小表示法+uva719
- 最小表示法
- 最小表示法
- poj1509最小表示法
- 字符串最小表示法
- poj1509 最小表示法
- 最小表示法
- poj1509 最小表示法
- 【模版】最小表示法
- 最小表示法
- [JAVA][HDU 1042][N!]
- 路径规划学习1
- SSH框架的简单搭建步骤
- [JAVA][HDU 1022][Train Problem I]
- resourcemanager.scheduler.SchedulerApplicationAttempt: Error trying to assign container解决
- 最小表示法
- [JAVA][HDU 1234][开门人和关门人]
- 2014世界互联网大会互联网领袖高峰对话实录
- linux备份还原(3)
- 2014-11-26QQ技巧
- OpenWrt系统安全改进<一>
- 设置UIBarButtonItem之间的距离【利用UIToolbar和UINavigationBar的关系】
- Jsoup 学习笔记
- Linux 命令——xargs 详解