编程艺术之第一章:左转字符串

题目描述:字符串的左转操作:将字符串前面的若干个字符移动到字符串的尾部。

    例如:把字符串abcdef 左旋转2位得到字符串cdefab。

要求:要求对字符串实现左旋转操作,并且对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1).

方法一、

我们可以讲字符串的左转想成如下过程:假设左转1个字符:

(1)、先把第一个字符提取出来;

(2)、后续的字符依次往前进一个;

(3)、完毕之后,把提取出来的第一个字符加到最后。

代码实现如下:

#include "LeftMoveChars.h"



void leftmovechars(char str[]);
int main()
{
	char str[] = "abcdef";//此字符串长度为7,记得'\0'
	printf("左转之前的字符串:%s\n",str);
	leftmovechars(str);
	printf("左转之后的字符串:%s\n",str);

	getchar();
	return 0;
}

void leftmovechars(char str[])
{
	char ch = str[0];
	for (int i = 1;i < 6;i++)
	{
		str[i-1] = str[i];
	}
	str[5] = ch;
	return;
}
运行结果如下图:


完成了一个字符串的旋转之后,假如要完成前n个字符串,只需要对上述操作循环n次就行:

修改后的代码如下:

修改leftmovechars为如下方法:

void leftmovechars_by_n(char str[],int n)
{
	for (int j = 0;j<n;j++)
	{
		char ch = str[0];
		for (int i = 1;i < 6;i++)
		{
			str[i-1] = str[i];
		}
		str[5] = ch;
	}
	return;
}

在主函数调用:

int main()
{
	char str[] = "abcdef";//此字符串长度为7,记得'\0'
	printf("左转之前的字符串:%s\n",str);
	//leftmovechars(str);
	leftmovechars_by_n(str,3);
	printf("左转之后的字符串:%s\n",str);

	getchar();
	return 0;
}

得到的运行结果如下:


如此我们就完成了字符串的左旋转。

但是该方法有个缺点,被移动的字符串都是一个个的被移动,由于考虑题目特点,被移动的字符串应当是整体的,可以被打包在一起整体移动的,所以我们可以采用下面的方法。

方法二、

主要思路如下:假设有7个长度的字符串abcdef‘\0’,左旋长度为3,那么将abc绑定在一起,依次往后移动

实现上可以设置两个指针p1、p2,分别指向第一个字符和第m个字符,这里的m是左旋长度

所以分别一一对应将两个数据交换,然后p1和p2分别向后移动。这里需要考虑两个问题,长度是否正好是旋转长度的整数倍,若不是,需要考虑p2指针移动长度不足的情况,此时只要把p2之后的数据和p1之后的数据有多少就交换多少就可以,而最后的'\0'不能被交换,否则系统会发生缺省读取'\0'之后的数据。

在最后不足长度的情况下做最后交换时,p1指针的最后一个数据优于无法和'\0'做交换,所以需要p1内部排序,将p1开始之后的数据全部赛到已交换的p1数据之后。

函数代码如下:

void leftmovechars_by_points(char str[],int n)
{
	//首先获取字符串的长度
	int length = 0;
	while (*(str+length)!='\0')
	{
		length++;
	}
	printf("字符串长度为:%d\n",length);
	//先定义两个指针,第一个指针指向第一个元素,第二个指针指向第n个元素;
	char* p1 = &str[0];
	char* p2 = &str[n];
	
	char temp;
	int mod = length % n;
	int x = length / n;
	if (0 == mod)
	{
		//从两个指针所指的位置开始两段长度为n的字符串的一一对应交换
		while ( x-- != 1)
		{
			for(int i = 0;i<n;i++)
			{
				temp = *p1;
				*p1 = *p2;
				*p2 = temp;
				p1++;
				p2++;
			}
		}
	}
	else
	{
		//首先先交换x-1次
		//从两个指针所指的位置开始两段长度为n的字符串的一一对应交换
		while ( x-- != 1)
		{
			for(int i = 0;i<n;i++)
			{
				temp = *p1;
				*p1 = *p2;
				*p2 = temp;
				p1++;
				p2++;
			}
		}
		while (*(p2)!='\0')
		{
			temp = *p1;
			*p1 = *p2;
			*p2 = temp;
			p1++;
			p2++;
		}
		if (*(p2) == '\0')
		{
			char* q = p1+1;
			for (int k = 0;k < n-1 ;k++)
			{
				temp = *p1;
				*p1 = *q;
				*q = temp;
				p1 = q;
				q = q++;
			}
		}
	}
	return;
}
程序运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值