zoukankan      html  css  js  c++  java
  • 字符串的最小表示法

    现在有个问题需要我们去解决,这个问题是这样的:

    有一个字符串,这个字符串的首尾是连在一起的,要求寻找一个位置,使得以该位置为起点的字符串的字典序在所有的字符串中最小

    最最暴力的做法就是用O(n)的时间枚举起始位置,O(n)的时间比对字符串的字典序,总的时间复杂度是O(n2),别想了,这种做法肯定不行。

    那我们再来看一个稍微朴素点的算法(看的时候最好自己在草稿纸上模拟一下

    我们设计ij两个指针。其中i指向最小表示的位置,j作为比较指针。

    初始时令i = 0,j = 1 

    如果S[i] > S[j] 则= j++

    如果S[i] < S[j] 则j++

    如果S[i]==S[j] 设指针k,分别从ij位置向下比较,直到S[i+k] != S[j+k]    

      如果S[i+k] S[j+k] 则= j++ 

      否则 j += k+1

    返回

    注意到,朴素算法的缺陷在于斜体的情况下i指针的移动太少了。针对这一问题改进就得到了最小表示法的算法。最小表示法的算法思路是维护两个指针ij

    初始时令i=0,j=1 

    如果S[i] > S[j] 则= j= i+1 

    如果S[i] < S[j] 则j++

    如果S[i]==S[j] 设指针k,分别从ij位置向下比较,直到S[i+k] != S[j+k]    

      如果S[i+k] > S[j+k] i += k+1

      否则j += k+1

    返回ij的较小者

     

    注意到上面两个算法唯一的区别是我用荧光笔刷出的那一行。这一行就把复杂度降到O(n)了。

    为什么会这样呢?其实我开始看半天也不知道为什么会这样,我后来测试了一下,对于同一道题目,第使用一种算法用了625ms,而第二种只用了16ms!!你就知道差别有多大了。

    按我的理解来说,第一种算法仅仅是用i维护了最小表示的位置,j不断往后进行比较;而第二种算法是比较完S[i+k]S[j+k]后根据情况来判断ij谁才是最小表示位置,对应的另外一个值去进行更新比较,这样ij都能用来维护了最小表示的位置,效率会高上很多,妙啊~这种思想好像在哪儿见过,具体的已经忘了,不过以后碰到了理解起来也会更加容易

    值得一提的是,可以应用最小表示法判断两个字符串是否同构,与KMP类似,最小表示法处理的是一个字符串S的性质,而不是看论文时给人感觉的处理两个字符串。 只要将两个串的最小表示求出来,然后从最小表示开始比较。剩下的工作就不用多说了。  

    Code

    int Get_min()
    {
        int n = strlen(s);
        int i = 0, j = 1, k = 0, t;
        //表示从i开始k长度和从j开始k长度的字符串相同
        while(i<n && j<n && k<n) {
            t = s[(i+k)%n] - s[(j+k)%n];
            //t用来计算相对应位置上那个字典序较大
            if(!t) k++;//字符相等的情况
            else {
                if(t>0) i += k+1; //i位置大
                else j += k+1; //j位置大
                if(i==j) j++;
                k = 0;
            }
        }
        return i >j ?j :i;
    }
    View Code

     参考文章:

    https://blog.csdn.net/li1615882553/article/details/80136776

    https://wenku.baidu.com/view/afcc12d4b14e852458fb571b.html

    https://www.cnblogs.com/XGHeaven/p/4009210.html

    https://www.cnblogs.com/justPassBy/p/5296275.html

    https://www.cnblogs.com/sweat123/p/4723265.html

  • 相关阅读:
    FindWindowEx使用方法
    什么是VSync
    getParameter
    高等数学积分公式大全
    为什么没有好用的Android游戏引擎?
    Best Time to Buy and Sell Stock III
    5.3 适配器模式(4.1)
    在动态网络下实现分布式共享存储
    人类智商一般在多少左右?爱因斯坦的智商是多少?
    海量数据处理面试题集锦
  • 原文地址:https://www.cnblogs.com/wizarderror/p/11353331.html
Copyright © 2011-2022 走看看