字符串的最小表示法

定义:给定一个字符串 S[1~n] ,如果我们不断把他的最后一个字符放到开头,最终会得到 n 个字符串,称这 n 个字符串是循环同构的。 这些字符串中字典序最小的一个,称为字符串 S 的最小表示。

例如 S = "abca",那么它的 4 个循环同构字符串为 "abca","aabc”,"caab","bcaa",S 的最小表示为 "aabc"。因为一个与 S 循环同构的字符串可以用该字符串在 S 中的起始下标表示,所以我们就用 B[i] 表示从 i 开始的循环同构字符串,即 S[i ~ n] + S[1 ~ i-1]。一个字符串的最小表示可以在 O(n) 的线性时间内求出。我们首先把 S 复制一份接在它的结尾,得到的字符串记为 SS 。显然, B[i] = SS[i ~ i+n-1]。

最小表示法:

1、初始化 i = 1,j = 2。

2、通过直接向后扫描的方法,比较B[i] 与 B[j] 两个循环同构串:

    (1)、如果扫描了 n 个字符后仍然相等,说明 S 只由一种字符构成,任意 B[i] 都是它的最小表示。

    (2)、如果在 i + k 和 j + k 处发现不相等:若 SS[i+k] > SS[j+k],令 i = i + k + 1。若此时 i = j,再令 i = i +1。

                 若 SS[i+k] < SS[j+k],令 j = j + k +1。若此时 i = j,再令 j = j+1。

3、若 i > n,B[j] 为最小表示;若 j > n,B[i] 为最小表示;否则重复第二步。

代码实现:

int n = strlen(s+1);
for(int i = 1; i <= n; i++) s[n+i] = s[i];
int i = 1, j = 2, k;
while(i <= n && j <= n){
    for(k = 0; k <= n && s[i+k] == s[j+k]; k++);
    if(k == n) break;//S只由一种字符构成,形如"aaaaa"
    if(s[i+k] > s[j+k]) {
        i = i + k + 1;
        if(i == j) i++;
    }else {
        j = j + k + 1;
        if(i == j) j++;
    }
}
ans = min(i,j);

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值