码迷,mamicode.com
首页 > 其他好文 > 详细

[算法]字符串左移k位

时间:2014-07-02 21:26:41      阅读:352      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   使用   strong   

如,abcde左移3位为deabc

要求时间复杂度O(n),空间复杂度O(1),每一个字符只能遍历一次

 

摘自http://blog.csdn.net/geniusluzh/article/details/8460031

利用数学解决该问题

    其实对于这道题,最初一看的想法就是将当前位依次替换左移m位对应的那个位,然后依次替换。后来发现有的情况一次循环替换就能全部完成整个串的左移,而有的情况下会出现多个循环链,一时只得到规律,不能想到很好的证明办法,只怪以前初等数论没有好好学啊!

    我们发现对于长度为n的串,左移m位,会形成gcd(n, m)个链,这里的gcd就是大家熟知的最大公约数,每个链的长度显然就是n/(gcd(n, m))。我们如何来证明这个问题呢?我们令i+j*m 和 i+k*m正好走了一圈又指向同一个元素,那么便是(i+j*m)%n == (i+k*m)%n,因此根据同余的性质我们知道n | (k-j)*m,而n = n‘ * gcd(n, m), m = m‘ * gcd(n, m)。所以我们得到n‘ | (k-j) * m‘, 由于n‘ 和 m‘ 互素,因此 n‘ | (k - j),因此我们知道最小的k-j = n‘ = n/gcd(n, m),也就是说一个循环链里头有n/gcd(n, m)个元素,因此总共有gcd(n, m)个循环链,于是得证。因此我们只需要取前gcd(n, m)个元素,每个走一条链进行循环的替换就行了。其实这个算法是最优的,真正的O(N)的时间复杂度,而且没有额外的开销。

 

int gcd(int m, int n){
    if(m < n){
        int t = m;
        m = n;
        n = t;
    }
    int r = m%n;
    while(r){
        m = n;
        n = r;
        r = m%n;        
    }
    return n;
} 
char* leftShift(char* str, int n, int k){
    char s, t;
    int g = gcd(n,k),len = n / g;
    for(int i = 0; i < g; ++i){
        s = str[i];
        for(int j = 0; j < len; ++j){
            t = str[(n - k + i)%n];
            str[(n - k + i)%n] = s;
            s = t;
            i = (n - k + i)%n;    
            times++;
        }
        
    }
    return str;
}

 

bubuko.com,布布扣
本文基于知识共享署名-非商业性使用 3.0 许可协议进行许可。欢迎转载、演绎,但是必须保留本文的署名林羽飞扬,若需咨询,请给我发信

[算法]字符串左移k位,布布扣,bubuko.com

[算法]字符串左移k位

标签:style   blog   http   color   使用   strong   

原文地址:http://www.cnblogs.com/zhengyuhong/p/3819030.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!