字符串左旋转问题

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

1.方法一

利用循环置换分解定理
所有序号为 (j+i *m) % n (j 表示每个循环链起始位置,i 为计数变量,m表示左旋转位数,n表示字符串长度),会构成一个循环链(共有gcd(n,m)个,gcd为n、m的最大公约数),每个循环链上的元素只要移动一个位置即可,最后整个过程总共交换了n次(每一次循环链,是交换n/gcd(n,m)次,总共gcd(n,m)个循环链。所以,总共交换n次)。
比如abcd,n=4,m=3
0*3%4=0;
1*3%4=3;
2*3%4=2;
3*3%4=1;
4*3%4=0;
上述的顺序正好跟abcd循环左移的顺序一样。如:
abcd循环移位变成dabc(这里m=3,n=4),ch[0]->temp, ch[3]->ch[0], ch[2]->ch[3],ch[1]->ch[2], temp->ch[1];

当n,m最大公约数大于1时,即有多个循环链,即用j表示。

代码:
#include<iostream>
#include<string>

using namespace std;

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

void leftReverse(string &str,int k){	
	int len=str.length();
	int cycleNum=gcd(len,k);
	int subLen=len/cycleNum;
	for(int j=0;j<cycleNum;j++){
		char tmp=str[j];
		int i;
		for(i=0;i<subLen-1;i++){
			str[(j+i*k)%len]=str[(j+(i+1)*k)%len];
		}
		str[(j+i*k)%len]=tmp;
	}
}

int main(){
	string str="abcd";
	leftReverse(str,3);
	cout<<str<<endl;
	system("pause");
	return 0;
}
用一个中间变量接连,使其循环。


方法二 

三旋转,(A'B')'=BA
#include<iostream>
#include<string>

using namespace std;

void reverse(string &str){
	int len=str.length();
	for(int i=0;i<len/2;i++){
		char tmp;
		tmp=str[i];
		str[i]=str[len-1-i];
		str[len-1-i]=tmp;
	}
}

int main(){
	string str="abcde";
	int len=str.length();
	int k=3;
	reverse(str.substr(0,k));
	reverse(str.substr(k,len-k));
	reverse(str);
	cout<<str<<endl;

	system("pause");
	return 0;
}

发现根本不是想要的结果,原来substr()返回的是一个新的字符串,对它进行操作不会影响原来的str。
#include<iostream>
#include<string>

using namespace std;

void reverse(string &str,int start,int end){//start指开始的下标,end指结束的下标
	for(int i=start;i<(end+start)/2;i++){//(end+start)/2中位数
		char tmp;
		tmp=str[i];
		str[i]=str[end-i];
		str[end-i]=tmp;
	}
}

int main(){
	string str="abcde";
	int len=str.length();
	int k=3;
	reverse(str,0,k-1);
	reverse(str,k,len-1);
	reverse(str,0,len-1);
	cout<<str<<endl;

	system("pause");
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值