旋转字符串

题目描述
定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab。
请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1)。 

一、指针翻转法

  咱们先来看个例子,如下:abc defghi,若要让abc移动至最后的过程可以是:abc defghi->def abcghi->def ghiabc

    如此,我们可定义俩指针,p1指向ch[0],p2指向ch[m];
一下过程循环m次,交换p1和p2所指元素,然后p1++, p2++;。

  1. 第一步,交换abc 和def ,abc defghi->def abcghi
  2. 第二步,交换abc 和 ghi,def abcghi->def ghiabc

    整个过程,看起来,就是abc 一步一步 向后移动

  • abc defghi
  • def abcghi
  • def ghi abc  

  //最后的 复杂度是O(m+n)  

由上述例子九个元素的序列abcdefghi,您已经看到,m=3时,p2恰好指到了数组最后一个元素,于是,上述思路没有问题。但如果上面例子中i 的后面还有元素列?

例子:

def ghi abc jk
当p1指向a,p2指向j时,由于p2+m越界,那么此时p1,p2不要变
这里p1之后(abcjk)就是尾巴,处理尾巴只需将j,k移到abc之前,得到最终序列,代码编写如下:

01.//copyright@July、颜沙     
02.//最终代码,July,updated again,2011.04.17。     
03.#include <iostream>     
04.#include <string>     
05.using namespace std;    
06.    
07.void rotate(string &str, int m)    
08.{    
09.        
10.    if (str.length() == 0 || m <= 0)    
11.        return;    
12.        
13.    int n = str.length();    
14.        
15.    if (m % n <= 0)    
16.        return;    
17.        
18.    int p1 = 0, p2 = m;    
19.    int k = (n - m) - n % m;    
20.        
21.    // 交换p1,p2指向的元素,然后移动p1,p2     
22.    while (k --)     
23.    {    
24.        swap(str[p1], str[p2]);    
25.        p1++;    
26.        p2++;    
27.    }    
28.        
29.    // 重点,都在下述几行。     
30.    // 处理尾部,r为尾部左移次数     
31.    int r = n - p2;    
32.    while (r--)    
33.    {    
34.        int i = p2;    
35.        while (i > p1)    
36.        {    
37.            swap(str[i], str[i-1]);    
38.            i--;    
39.        }    
40.        p2++;    
41.        p1++;    
42.    }    
43.    //比如一个例子,abcdefghijk     
44.    //                    p1    p2     
45.    //当执行到这里时,defghi a b c j k     
46.    //p2+m出界 了,     
47.    //r=n-p2=2,所以以下过程,要执行循环俩次。     
48.        
49.    //第一次:j 步步前移,abcjk->abjck->ajbck->jabck     
50.    //然后,p1++,p2++,p1指a,p2指k。     
51.    //               p1    p2     
52.    //第二次:defghi j a b c k     
53.    //同理,此后,k步步前移,abck->abkc->akbc->kabc。     
54.}    
55.    
56.int main()       
57.{       
58.    string ch="abcdefghijk";       
59.    rotate(ch,3);       
60.    cout<<ch<<endl;       
61.    return 0;          
62.}      


 

二、三步翻转法

将一个字符串分成两部分,X和Y两个部分,在字符串上定义反转的操作X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么我们可以得到下面的结论:(X^TY^T)^T=YX。显然我们这就可以转化为字符串的反转的问题了。

不是么?ok,就拿abcdef 这个例子来说,若要让def翻转到abc的前头,那么只要按下述3个步骤操作即可:
1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。

 

//Copyright@ 小桥流水 && July  
//c代码实现,已测试正确。  
//http://www.smallbridge.co.cc/2011/03/13/100%E9%A2%98  
//_21-%E5%B7%A6%E6%97%8B%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2.html  
//July、updated,2011.04.17。  
#include <stdio.h>  
#include <string.h>  
  
char * invert(char *start, char *end)  
{     
    char tmp, *ptmp = start;      
    while (start != NULL && end != NULL && start < end)    
    {     
        tmp = *start;     
        *start = *end;        
        *end = tmp;       
        start ++;     
        end --;   
    }  
    return ptmp;  
}  
  
char *left(char *s, int pos)   //pos为要旋转的字符个数,或长度,下面主函数测试中,pos=3。  
{  
    int len = strlen(s);  
    invert(s, s + (pos - 1));  //如上,X->X^T,即 abc->cba  
    invert(s + pos, s + (len - 1)); //如上,Y->Y^T,即 def->fed  
    invert(s, s + (len - 1));  //如上,整个翻转,(X^TY^T)^T=YX,即 cbafed->defabc。  
    return s;  
}  
  
int main()  
{     
    char s[] = "abcdefghij";      
    puts(left(s, 3));  
    return 0;  
}  


以上两个均符合复杂度的要求。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值