zoukankan      html  css  js  c++  java
  • 最小表示法

    咳咳,我又回来了,有大半个月没更新了,最近我在刷题的时候刷到一个很有意思的字符串的题。
    题目大概长成这样:

    给定一个循环字符串S的一个周期

    题目求S的字典序最小的周期

    (比如 abc,bca,cab都是同一个循环字符串,这个循环字符串的最小表示是abc)

    Input

    有多组数据

    每组数据只有一行

    是只由小写字母组成的字符串

    每行字符个数不超过20万

    总字符个数不超过100万

    Output

    输出S的字典序最小的一个周期

    SampleInput
    aabaaaaabb
    bbbababa
    bbacccca
    baddd
    
    SampleOutput
    aaaaabbaab
    abababbb
    abbacccc
    adddb
    我当时拿到题目也没多想,直接暴力,毕竟是环嘛,从头到尾,暴力搜索一边就好了,然鹅....
    TLE了QAQ,当时看了下数据量足足100W,也不知道怎么做,然后去网上搜了下大佬的博客,发现这也是一个算法叫作 最小表示法
    它的复杂度好像是O(n),自然效率高得多,然后AC了,还是蛮有意思的算法,下面看看吧。
    这个最小表示法,原理大概是这样:
    把已经比较过相等的字符跳过,从最后一个相等的字符的下一个字符开始比较字典序。这里需要用到两个指针i,j,
    Of Course,你也可以把这两个指针名字改一,然后令i=0,j=1 k=0(或者换一下i=1.j=0,然是必须保证从字符串的头开始)
    然后依次判断第i+k个位置字符和第j+k个位置的字符的关系
    1> 当第i+k个位置的字符等于第j+k(不是DJ!=_=)个位置的字符的时,k++;
    2> 当第i+k个位置的字符小于第j+k个位置的字符时,j=j+k+1;(因为第i+k个位置之前的位置的字符和第j+k个位置之前的位置的字符都是相等的,第i+k个位置小于j+k,说明第i个位置的字符比j更优,保留i,j+=k+1);
    3> 当第i+k个位置的字符大于第j+k个位置的字符时,i=i+k+1;

    (因为第i+k个位置之前的位置的字符和第j+k个位置之前的位置的字符都是相等的,第i+k个位置大于j+k,说明第j个位置的字符比i更优,保留j,i+=i+1);

    4>当遍历完成时,取i,j之中最小的就是字典序最小的循环同构串。
    这里面还有几个注意的地方:1>用k递增的时候要对i+k对数组长度取模,防止溢出;
    2>每次第i+k个元素!=第j+k个元素的时候将k置零;
    3>当i==j时,变化的指针++,要让i,j指针不在同一个位置;
    这大概就是这个算法的大体思路,下面我给出源代码:

    #include<bits/stdc++.h>
    using namespace std;
    int len;
    char c[200005];
    int main(void)
    {
        while(~scanf("%s",c))
        {
            int cout=0,i=0,j=1,k=0;
            len=strlen(c);
            while(i<len&&j<len&&k<len)
            {
                int t=c[(i+k)%len]-c[(j+k)%len];
                if(!t)
                k++;
                else
                {
                if(t>0)
                {
                i=i+k+1;
                if(i==j)
                i++;
                }
                else
                {
                j=j+k+1;
                if(i==j)
                j++;
                }
                k=0;
                }
            }
            cout=min(i,j);
            for(int i=0;i<len;i++)
            printf("%c",c[(i+cout)%len]);
            printf("
    ");
            memset(c,0,sizeof(c));
        }
        return 0;
     } 

    当然在那个内层while循环那里还可以写一个for循环,也能达到效果。
    这个算法思路很简单,也很有意思,在O(n)的时间复杂度就找到了最小串。 

    OVER

  • 相关阅读:
    微信公众号验证域名
    go在mac上打其他平台包
    screen窗口化管理守护进程
    kettle字符串null转空串
    MAC M1安装kettle spoon
    删除git文件版本控制
    LNMP状态管理命令
    事务处理
    精通 JS正则表达式
    php日期转时间戳,指定日期转换成时间戳
  • 原文地址:https://www.cnblogs.com/Mangata/p/12548349.html
Copyright © 2011-2022 走看看