左旋转字符串

学习July的程序员编程艺术的小结

原文地址:点击打开链接

题目描述:

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

算法描述:

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

不是么?ok,就拿abcdef 这个例子来说(非常简短的三句,请细看,一看就懂):
1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。

代码实现:

#include <iostream>

//字符串反转函数
char* invert(char *start,char *end)
{
	char tmp,*ptemp=start;
	while(start!=NULL && end!=NULL && start<end)
	{
		tmp = *start;
		*start = *end;
		*end = tmp;
		start++;
		end--;
	}

	return ptemp;
}
//字符串左旋函数
char* left(char *s,int pos)
{
	if(s==NULL)
		return s;
	int len = strlen(s);
	pos = pos % len;
	invert(s,s+(pos-1));
	invert(s+pos,s+(len-1));
	invert(s,s+(len-1));

	return s;
}

int main()
{
	char s[] = "abcdefghij";

	std::cout<<"左旋前:"<<s<<std::endl;
	std::cout<<"左旋后:"<<left(s,3)<<std::endl;

	return 0;
}

方法二:

算法描述:

所有序号为 (j+i *m) % n (表示每个循环链起始位置,i 为计数变量,m表示左旋转位数,n表示字符串长度),

  会构成一个循环链(共有gcd(n,m)个,gcd为n、m的最大公约数),每个循环链上的元素只要移动一个位置即可,

  最后整个过程总共交换了n次(每一次循环链,是交换n/gcd(n,m)次,总共gcd(n,m)个循环链。所以,总共交换n次)。

通过前面思路的阐述,我们知道对于循环移位,最重要的是指针所指单元不能重复。例如要使abcd循环移位变成dabc(这里m=3,n=4),

   经过以下一系列眼花缭乱的赋值过程就可以实现:
    ch[0]->temp, ch[3]->ch[0], ch[2]->ch[3], ch[1]->ch[2], temp->ch[1];  (*)
    字符串变化为:abcd->_bcd->dbc_->db_c->d_bc->dabc;

代码实现:

#include <iostream>
#include <string>

int gcd(int a,int b)
{
	//求最大公约数
	int common = a%b;
	while(common)
	{
		a = b;
		b = common;
		common = a%b;
	}
	return b;
}

void rotate(std::string& str,int m)
{
	int lenOfStr = str.length();
	int NumOfGroup = gcd(lenOfStr,m);
	int ElementInSub = lenOfStr / NumOfGroup;
	for(int j=0;j<NumOfGroup;++j)
	{
		char tmp = str[j];
		int i;
		for(i=0;i<ElementInSub-1;++i)
		{
			str[(j+i*m)%lenOfStr] = str[(j+(i+1)*m)%lenOfStr];
		}
		str[(j+i*m)%lenOfStr] = tmp;

		std::cout<<str<<std::endl;
	}
}

int main()
{
	std::string str = "abcdefghij";

	std::cout<<"左旋前:"<<str<<std::endl;
	int m = 5;
	rotate(str,m);
	std::cout<<"左旋后:"<<str<<std::endl;

	return 0;
}

没想到小小的字符串左旋居然存在这么深的问题。特别是这两个算法实在是太神奇了!!!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值