hdu3374 String Problem (字符串最小表示)
来源:互联网 发布:龙泉驿广电网络全称 编辑:程序博客网 时间:2024/05/17 05:13
题目:
输出一个字符串的最小表示时起始位置和最大表示时起始位置。并输出有多少个最小表示和最大表示。
分析:
循环字符串的最小表示法的问题可以这样描述:
对于一个字符串S,求S的循环的同构字符串S’中字典序最小的一个。
由于语言能力有限,还是用实际例子来解释比较容易:
设S=bcad,且S’是S的循环同构的串。S’可以是bcad或者cadb,adbc,dbca。而且最小表示的S’是adbc。
对于字符串循环同构的最小表示法,其问题实质是求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起初,我想在j指针后移的过程中加入一个优化。就是j每次不是加1,而是移动到l位置。其中,l>j且S[l]<=S[j]。但是,即使加入这一优化,在遇到bbb…bbbbbba这样的字符串时复杂度将退化到O(n^2)。
注意到,朴素算法的缺陷在于斜体的情况下i指针的移动太少了。针对这一问题改进就得到了最小表示法的算法。最小表示法的算法思路是维护两个指针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的小者注意到上面两个算法唯一的区别是粗体的一行。这一行就把复杂度降到O(n)了。
值得一提的是,与KMP类似,最小表示法处理的是一个字符串S的性质,而不是看论文时给人感觉的处理两个字符串。
应用最小表示法判断两个字符串同构,只要将两个串的最小表示求出来,然后从最小表示开始比较。剩下的工作就不用多说了。
根据上面的分析,不难写出代码。
代码:
#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <vector>#include <map>#include <set>#include <cmath>#include <cstdlib>#include <cstring>#include <cstdio>using namespace std;#define ms(a,b) memset(a,b,sizeof(a))#define lson rt*2,l,(l+r)/2#define rson rt*2+1,(l+r)/2+1,rtypedef unsigned long long ull;typedef long long ll;const int MAXN = 1e6 + 5;const double EPS = 1e-8;const int INF = 0x3f3f3f3f;const int MOD = 1e9 + 7;char s[MAXN];int n, nxt[MAXN];void getnext() { nxt[0] = 0; for (int i = 1; i < n; i++) { int j = nxt[i - 1]; while (s[i] != s[j] && j > 0) j = nxt[j - 1]; if (s[i] == s[j]) nxt[i] = j + 1; else nxt[i] = 0; }}int getmin(){ int i=0,j=1,k=0; while(i<n&&j<n&&k<n) { int t=s[(i+k)%n]-s[(j+k)%n]; if(!t) k++; else { if(t>0) i+=k+1; else j+=k+1; if(i==j) j++; k=0; } } return min(i,j); } int getmax() { int i=0,j=1,k=0; while(i<n&&j<n&&k<n) { int t=s[(i+k)%n]-s[(j+k)%n]; if(!t) k++; else { if(t>0) j+=k+1; else i+=k+1; if(i==j) j++; k=0; } } return min(i,j); } int main() { while (~scanf("%s", s)) { n = strlen(s); getnext(); int mi = getmin(), mx = getmax(); int cir = n - nxt[n - 1]; int times = 1; if (n % cir == 0) times = n / cir; printf("%d %d %d %d\n", mi + 1, times, mx + 1, times); } return 0;}
- hdu3374 String Problem (字符串最小表示)
- HDU3374(String Problem)字符串-最小表示法+KMP
- HDU3374 String Problem(KMP + 最大最小表示)
- hdu3374 String Problem(KMP+最小表示法)
- HDU3374 String Problem(KMP + 最小表示法)
- hdu3374 String Problem(最小最大表示法+KMP)
- hdu3374-最小表示法&&kmp求循环节-String Problem
- HDU3374 String Problem(kmp,最大最小表示法)
- hdu3374 String Problem
- 【KMP】 hdu3374 String Problem
- hdu3374 String Problem
- hdu3374---String Problem
- hdu3374最大最小表示+kmp
- hdu3374 最小表示法+kmp
- hdu3374(最小表示法+KMP)
- hdu3374最小表示法+KMP
- String Problem (最小表示法+KMP)
- hdu 3374 String Problem(KMP+字符串最小最大表示)
- -----hdu 5073-Galaxy
- BootStrap的modal模态框的使用
- Pandas学习
- metasploit学习1
- CCS中的文注释乱码问题
- hdu3374 String Problem (字符串最小表示)
- 【安全牛学习笔记】DNS信息收集-DIG
- Mysql中的count()与sum()区别
- vue router-view详细讲解一
- arm-poky-linux-gnueabi- (5.3.0) 工具链编译live555-20170718
- Js使用arguments动态获取传参个数
- 使用cocos studio界面自适应遇到问题及解决方法
- aar 文件配置
- LeetCode 312: Brust Balloon 解题与思考