字符串左旋满足时间复杂度为O(n)

    字符串左旋转解释:例:原字符串为abcd,左旋转两位则为:cdab

    题目:实现字符串的左移,左移n位,要求对长度为n的字符串操作的时间复杂度为O(n)

   对于数组循环移位问题,真正靠谱的其实只有两种,一种是前后部分逆置法,一种是利用gcb算法新得到的字符串左旋转法。直接贴出程序欲与解释。

    方法一:

//时间2012.5.24
//程序目的:实现字符串的左移,左移n位,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度是O(1)
//解析:拿abcdef为例
       /*
         1、首先将字符串abcdef分为两个部分,X:abc Y:def
         2、X->X^T,abc->cba,Y->Y^T,def->fed
         3、(X^TY^T)^T = YX, cbafed->defabc
       */


#include <stdio.h>
#include <string.h>


//invert函数主要用于分部分逆转字符串,例abcd变成dcba
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;
}


//将一个字符串分成两部分分别逆转后在将整个字符串逆转记得到左移pos位。
char * left(char *s, int pos)
{
if(s == NULL)
return s;
int len = strlen(s);
pos%=len;
if (pos>0 && pos<=len)
{
   invert(s, s+pos-1);
   invert(s+pos, s+len-1);
   invert(s,s+len-1);
}
return s;
}


int main()
{
char s[] = "abcdefghijklm";
puts (left (s,15)); //将字符串s左移3位
    return 0;
}


/*
输出结果:
defghijklmabc
Press any key to continue
*/


方法二:

//时间:2012.5.26
//算法目的:包含gcb算法的左旋m位算法,其主要思路为
           /*
  1、判断字符串总长度n和左旋位数m是否是互质数
  2、若是互质数则直接进行移位
  3、若不是互质数则先找出m和n的最大公约数,记为k。之后将链表分割成k个小链表,在进行移位
           */
//重点:
       /*
  1、知道什么是gcb算法,gcb算法就是求两个数最大公约数的算法,其流程是:
         假设两个数是m和n,要保证m>n
 r = m%n;
 若r = 0,直接返回最大公约数,为n。
 若r != 0,则
     让 m = n; n = r; r = m%n,知道r = 0,返回n。
  2、学会这种左旋的方法,知道其所以然
       */
#include <stdio.h>
#include <string.h>




//判断两个数是否是互质数。互质数:两个数只能同时被1整除
int primenumber(int len, int leftlen)
{
int flag = 0;
for(int i=2; i<=leftlen; i++)
{
if ((leftlen%=i) == 0)
{
if((len%=i) == 0)
flag = 1;//表示不是互质数
}
}
   return flag;
}


//若两个数是互质数,只进行内部调整,即左旋转leftlen位数
char * inverse(char *str, int len, int leftlen)
{
char *newstr = str;
    char tmp = str[0];


for (int i = 0; i < len-1; i++)
{
  str[(i*leftlen) % len] = str[((i+1)*leftlen) % len];
}
    str[(i*leftlen) % len] = tmp;



return newstr;
}


//找出两个数的最大公约数,采用gcb算法
int gcb(int m, int n) //全程必须使m > n,由于len >= leftlen,所以刚开始时不用判断
{
int r;
r = m%n;
while (r)
{
m = n;
n = r;
if (m < n) //时刻保证m>n
{
int k = m ;
m = n;
n = k;
            r = m%n;
}
}
return n;
}


//若两个数不互为质数,则先将链表分割成几个小链表后分别调用inverse()
char * notprimenumber(char *str, int len, int leftlen)
{
int k = gcb(len, leftlen);
char *newstr = str;
   
for (int j=0; j<k; j++)

char tmp = str[j];
    for (int i = 0;i < (len-1)/2; i++)
{
      str[(j + i*leftlen) % len] = str[(j + (i+1)*leftlen) % len];
}
        str[(j + i*leftlen) % len] = tmp;
}
return newstr;
}


int main()
{
char str[] = "abcdefgh";
int leftlen, flag;
int len = strlen(str);
printf ("字符串的长度为:%d\n", len);
printf ("请输入您要左移的位数:\n");
scanf("%d", &leftlen);
leftlen %= len;//让左移的位数小于字符串的总长度
flag = primenumber (len, leftlen);
printf ("左移后的字符串为:\n");
if (flag == 1)
{
puts( notprimenumber (str, len, leftlen) );
}
else
{
puts (inverse (str, len, leftlen));
}


return 0;
}


/*
算法运行结果:
字符串的长度为:8
请输入您要左移的位数:
4
左移后的字符串为:
efghabcd
Press any key to continue
*/


学习参照网址:http://blog.csdn.net/v_july_v/article/details/6245939#

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值