字符串旋转与移位

     在好多字符串处理中,旋转与移位是很常见到的,在大规模的数据处理中设计高效的算法是必须的

示例:

把字符串abcdefgh循环左移3位,变为defghabc

输入字符串str与移位数m,输出结果

1、看到题之后一般的想法就是一位一位的移动

  • abcdefgh
  • bcdefgha
  • cdefghab
  • defghabc

      实现代码如下

 

[cpp]  view plain copy
  1.   
[html]  view plain copy
  1. void movebit(string &str,int num)  
  2. {  
  3.     int len=str.length();  
  4.     for (int i=0;i<num;++i)  
  5.     {  
  6.         char temp=str[0];  
  7.         for (int j=1;j<len;++j)  
  8.         {  
  9.             str[j-1]=str[j];  
  10.         }  
  11.         str[--j]=temp;  
  12.     }  
  13. }  


        这样算法的时间复杂度为O(m*n)

2、在第一种方法中是一个字符一个字符的向后移动,这样后边的字符也得跟着移动m次,那么能不能一次就向后移动m个字符呢,答案是肯定的,这就是第二种方法,一次向后移动m个字符

  • abcdefgh
  • defabcgh
  • defghcab
  • defghabc

示例代码如下:

[cpp]  view plain copy
  1. void movechar(string & ch,int num)  
  2. {  
  3.     int len=ch.length();  
  4.     if (len<=0||num>=len)  
  5.     {  
  6.         return;  
  7.     }  
  8.     int first=0;                    //第一次交换的字符位置  
  9.     int middle=num;  
  10.     int second=middle;              //与之交换的位置  
  11.       
  12.     while (1)  
  13.     {  
  14.         char temp=ch[first];  
  15.         ch[first]=ch[second];  
  16.         ch[second]=temp;  
  17.         first++;  
  18.         second++;  
  19.         if (first==middle)  
  20.         {  
  21.             if (second>=len)        //交换完成,退出  
  22.             {  
  23.                 return;  
  24.             }  
  25.             else                    //进行下一轮交换  
  26.             {  
  27.                 middle=second;  
  28.             }  
  29.         }  
  30.         else if (second>=len)       //前半部分长,后半部分短,如defg abc h  
  31.         {  
  32.             second=middle;  
  33.         }  
  34.     }  
  35. }  


3、接下来这种方法是利用字符串的翻转

     先把字符串按移位的个数分为两部分,abc 与 defgh

     思想是先对第一部分反转交换,第一个与最后一个交换,依次类推,交换之后分别为 cba 与 hgfed

     最后对所得的字符串cbahgfed整体翻转,结果为defghabc,即我们要得到的结果

    实现代码如下:

    字符串翻转函数:

[cpp]  view plain copy
  1. void revote(char *ch,int start,int end)  
  2. {  
  3.     char temp;  
  4.     while (start<end)  
  5.     {  
  6.         temp=ch[start];  
  7.         ch[start]=ch[end];  
  8.         ch[end]=temp;  
  9.         ++start;  
  10.         --end;  
  11.     }  
  12. }  
[cpp]  view plain copy
  1. void translate(char * ch,int num)  
  2. {  
  3.  if (ch==NULL||num<=0||num>=strlen(ch))  
  4.  {  
  5.   return;  
  6.  }  
  7.  revote(ch,0,num-1);                   //对前一部分翻转  
  8.  revote(ch,num,strlen(ch)-1);          //对后一部分翻转  
  9.  revote(ch,0,strlen(ch)-1);            //整体翻转  
  10. }  


4、最后一种方法是用最大公约数法,移动字符

     利用公式  index=(i+m*j)%n

    设m与n的最大公约数为k,则i为从0到k-1循环k次

    如在示例中m=3,n=7,最大公约数为1,所以i只为0

    下标计算结果为:0,3,6,2,5,1,4,0

     依照这样的顺序进行移位,最后得到最终的结果

   实现代码如下:

[java]  view plain copy
  1. //用辗转相除法求最大公约数函数  
  2. int GCD(int m,int n)  
  3. {  
  4.     if (n==0)  
  5.     {  
  6.         return m;  
  7.     }  
  8.     else   
  9.     {  
  10.         return GCD(n,m%n);  
  11.     }  
  12. }  
[java]  view plain copy
  1. <pre class="cpp" name="code">void Rotate(string &str,int num)  
  2. {  
  3.     int len=str.length();  
  4.     int commonNum=GCD(len,num);                    //求出的最大公约数  
  5.     int time=len/commonNum;                        //计算内循环次数  
  6.     for (int i=0;i<commonNum;++i)  
  7.     {  
  8.         char temp=str[i];  
  9.         for (int j=0;j<time-1;++j)  
  10.         {  
  11.             str[(i+j*num)%len]=str[(i+(j+1)*num)%len];  //下标计算 (i+j*num)%len  
  12.         }  
  13.         str[(i+j*num)%len]=temp;  
  14.     }  
  15. }</pre><br>  
  16. <pre></pre>  
  17. <p><span style="font-size:16px">小结:总共介绍了4中字符串旋转的方法,其中第四种字符移动次数最少</span></p>  
  18. <pre></pre>  
  19. <pre></pre>  
  20. <pre></pre>  
  21. <pre></pre>  
  22. <pre></pre>  
  23. <pre><span style="font-size:16px">当然,如果是循环右移m位,可以转变为循环左移n-m位</span></pre>  
  24. <pre></pre>  
  25.       
  26.         <div style="padding-top:20px">           
  27.             <p style="font-size:12px;">版权声明:本文为博主原创文章,未经博主允许不得转载。</p>  
  28.         </div>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值