算法研究(一) 旋转字符串的三种算法

题目:给定一个长度为n的字符串,将它向左旋转i个位置,例如,str = "abcdefg", n = 7, i = 3,则旋转后,str = "defgabc",要求空间复杂度为1。

一般,解旋转字符串这样的题目,最简单的做法即是先将前i个字符拷贝到临时空间,然后将后n - i个字符前移,最后再将临时空间中的数据拷贝到原字符串的后i个位置上。但这样做会额外浪费i个空间。现给出如下三种算法:

• 算法一:

void swap(char* str, int n, int i){                                                                                                                 

    int j;
    for (j = 0; j < i; ++j) {

        int t = str[j];
        str[j] = str[n - i + j];
        str[n - i + j] = t;
    }
}

void rotate(char* str, int n, int i) {
    
    if (0 == i || n == i)
        return;

    int k = n - i;
    if (i < k) {
        swap(str, n, i);
        rotate(str, n - i, i);
    }
    else {
        swap(str, n, k);
        rotate(str + k, n - k, i - k);
    }
}

算法二:

void reverse(char*str, int n) {

    int m = n / 2;
    int i;
    for (i = 0; i < m; ++i) {

        int t = str[i];
        str[i] = str[ n - 1 - i];
        str[n - 1 - i] = t;
    }
}

void rotate(char* str, int n, int i) {

    reverse(str, i);
    reverse(str + i, n - i);
    reverse(str, n);
}

• 算法三:

int gcd(int m, int n) { 

    int k = m % n;
    if (0 == k)
        return n;
    else
        return gcd(n, k);
}

void rotate(char* str, int n, int i) {

    int k = gcd(n, i);
    int init;
    for (init = 0; init < k; ++init) {
        
        int cur = init;
        char t = str[cur];
        int next;
        for (next = (cur + i) % n; next != init; next = (cur + i) % n) {

            str[cur] = str[next];
            cur = next;
        }   
        str[cur] = t;
    }
}

不难看出,这三种算法的空间复杂度都是1,而时间复杂度都是n。但,算法三实际上更加巧妙,它所用时间只是前两者的一半。

(注:最近看了STL关于rotate函数的源码,发现它这三种算法都用到了,其对应的迭代器 concept 分别是 ForwardIterator, BidrectionalIterator, RandomaccessIterator,不过我觉得由于前两种算法的效率是一样的,所以实际上不需要 BidrectionalIterator 版的算法。)

参考文献

《编程珠玑》(美)本特利(Bentley,J.)


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值