腾讯面试题--字符串旋转

首先,说明一下。我看过题解,至于文章算不算原创,我就不敢保证了。如果,不算原创,咱在这就对不起了。

题意呈上,望主子能理解:给你一串文本串str位移数k,现在让你在O(n)的时间复杂度,与O(1)的空间复杂度,是的原来的文本串整体位移K位。

例如:str = "abcdefg", k = 3;那么结果就应该是defgabc


目前为止:已经想到有3种方案,欢迎补充。


 方案一:看题解的做法是:

1.假设串长为n;

2.先将原串分为两个字串;

3.如果左移那么就是str[0 … k-1]与str[k…n-1],反之为str[0 … len-k-1]与str[len - k - 1…n-1];

4.将两个字串各自翻转得到整体的str

5.再将最后的str翻转即可。

这样时间刚刚好为O(N);

演示一遍:str = "abcdefg", k = 3

1.n = strlen(str);

2.str[0…2] = “abc” str[3…6] = “defg”

3.翻转字串,得到str=“cbagfed”

4.最后在讲str翻转得:str = “defgabc”


方案二:自己的想法,不知道正确与否;

1.从原串中任意一处出发;

2.然后使用记录当前的位置上的字符,赋给想移位k的地方;

3.一直循环下去,知道循环位置达到n次后就停止;

例如:str=“abcd” k = 3 。我的初始地点第一位,那么可以得到:

第一趟:aacd ch=‘b’

第二趟:aabd ch=‘c’

第三趟:aabc ch=‘d’

第四趟:dabc 结束。


当str=“abcde” k=2是,我的思路如上图。

可后来我们考虑一下,如果如果n % k == 0,结果就不对,只是因为n = k * x,x为一个循环节。所以遇到此情况我们要特判。向前向后移一位继续进行下去,不过我不是很清楚这种方案是否可行。望大神指导,在下不甚欢喜。


方案三:这个方案来自于我的师弟;

1.将str[0…k - 1]与str[k…2*k- 1]交换,以此类推;

2.当出现len-xk<k时就改变k的循环节,使k=xk+k-len-1;

3.重复1,2步骤;直至到达最后的len。

例如:abcdefg  4

第一趟:efgdabc k=1

第二趟:efgadbc k = 1

第三趟:efgabdc k = 1

第四趟:efgabcd 结束


最后,电脑没装作图的,只能随便画了下,见谅。

第一次,写博客,见谅。

附代码两份,代码比较戳,见谅。

#include <iostream>//自己的思路代码
using namespace std;
#include <cstring>
#include <string>
const int MAX = 100 + 10;
char str[MAX];

//int res(char *str, int )

int main()
{
	int k, num, start, i;//start表示循环次数,num表示是否回到了循环起点,i跳转点。
	char ch, s;

	while (cin >> str >> k)
	{
		int len = strlen(str);
		ch = str[len - 1];
		start = 0, i = len - 1;
		num = len - 1;

		while (start++ < len)
		{
			s = str[(i + len - k) % len];
			str[(i + len - k) % len] = ch;
			ch = s;
			i = (i + len - k) % len;

			if (i == ((num + k + len) % len) && start != len)//当发现找到循环节点,我们就将i移向下一位即可。
			{
				str[num] = ch;
				start++;
				ch = str[(i + len + 1) % len];
				num = i = (i + len + 1) % len;
			}
		}

		puts(str);
	}
	return 0;
}

#include <iostream>//题解所述的代码
using namespace std;
#include <cstring>
#include <string>
const int MAX = 100 + 10;
char str[MAX];
int sum;

void resarse(char *str, int start, int end)
{
	while (start < end)
	{
		swap(str[start], str[end]);
		start++;
		end--;
		sum++;
	}
}

int main()
{
	int k;

	while (cin >> str >> k)
	{
		int len = strlen(str);
		k %= len;
		sum = 0;

		resarse(str, 0, k - 1);
		resarse(str, k, len - 1);
		resarse(str, 0, len - 1);

		puts(str);
		printf("%d\n", sum);
	}
	return 0;
}


#include <iostream>//方案三
using namespace std;
const int MAX = 100 + 10;
char str[MAX];

bool change(char *str, int start, int end, int k)
{
	for(int i = start; i < end; i++)
	{
		if (end - i - 1 >= k)
		{
			swap(str[i], str[i + k]);
			if (end - i - 1 == k && end % k == 0) return true;//找到最后一个循环节点
		}
		else
		{
			if (end == i + 1) return true;
			k = k + i - end + 1;//将循环节点改变,类似于辗转相除
			if (change(str, i, end, k)) return true;
		}
	}
}

int main()
{
	int k, i;

	while (cin >> str >> k)
	{
		int len = strlen(str);
		change(str, 0, len, k);
		puts(str);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值