字符串左右旋转问题

首先说明下所谓"字符串左右旋转"是指什么:

如字符串"abcdefg"左旋2位,结果应该是"cdefgab";再对"cdefgab"右旋2位,结果应该是"abcdefg",即:

左旋n位:字符串的前n位由首部移到尾部,右旋n位:字符串的后n位由尾部移到首部。n < strlen(字符串)


1、直观的常规方法:

直观方法就是依次移位,比如abcdefg,需要左旋2位,那么先把a移位到尾部使字符串变成bcdefga,然后再把b移位到尾部是字符串变成cdefgab。

每个字符的一次直接移位的时间复杂度是O(N),如果需要移位n个字符,那么时间复杂度就是O(n * strlen(字符串))


2、O(N)的方法:

采取"先交换最后移位"的方式,依然以abcdefg左旋2位为例,先连续进行2次"交换",依次变为cdabefg、cdefabg,这时候长度已经不能再交换了,就对最后的abg进行移位变为gab,最终结果就是cdefgab。交换、移位的时间复杂度都是O(N),所以整个操作的时间复杂度也是O(strlen(字符串)):

完整程序含测试程序如下:

#include <iostream>
#include <stdlib.h>


//p[0: num-1]与p[num: num * 2 - 1]交换数据(O(N))
void swap (char *p, int num) {
	for (int i = 0; i < num; i++) {
		char tmp = p[i];
		p[i] = p[i + num];
		p[i + num] = tmp;
	}
}

//abcde变为eabcd(O(N))
void leftshift (char *p, int num) {
	char rightest = p[num];
	for (int i = num; i > 0; i--) {
		p[i] = p[i - 1];
	}
	p[0] = rightest;
}

//abcde变为bcdea(O(N))
void rightshift (char *p, int num) {
	char leftest = p[0];
	for (int i = 0; i < num; i++) {
		p[i] = p[i + 1];
	}
	p[num] = leftest;
}

//还能整块交换的时候就整块交换, 不能交换的时候就移位. rotate和shift的时间复杂度都是O(N), 所以整个操作也是O(N)的时间复杂度
void leftrotate (char *p, const char *q, int num) {
//当前指针离字符串末尾如果不足两倍交换的长度, 就该移位了. 否则继续整块交换
	if (q - p >= (num * 2)) {
		swap(p, num);
		p = p + num;
		leftrotate(p, q, num);
	} else {
		for (int i = 0; i < num; i++) {
			rightshift(p, q - p);
		}
		return;
	}
}


void rightrotate (char *p, const char *q, int num) {
	if (p - q >= (num * 2)) {
		swap(p - num * 2 + 1, num);
		p = p - num;
		rightrotate(p, q, num);
	} else {
		for (int i = 0; i < num; i++) {
			leftshift(p - (p - q), p - q);
		}
	}
}

int main (int argc, char *argv[]) {
	char *raw = argv[1];
	char *res = new char(strlen(raw) + 1);
	memcpy(res, raw, strlen(raw));
	res[strlen(raw)] = '\0';
	std::cout << res << std::endl;
	
	int num = atoi(argv[2]);
	leftrotate(res, (const char *)&res[strlen(res) - 1], num);
	std::cout << res << std::endl;
	rightrotate(&res[strlen(res) - 1], (const char *)res, num);
	std::cout << res << std::endl;
	delete res;
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值