《剑指offer》之“左旋数组”的四种实现

一、引例 - 牛客网OJ题

为了更好地说明这个问题,我们以一道牛客网的题目作引例。题目链接贴在这里

左旋转字符串_牛客题霸_牛客网汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指。题目来自【牛客题霸】icon-default.png?t=N7T8https://www.nowcoder.com/practice/12d959b108cb42b1ab72cef4d36af5ec?fromPut=????_pc_????_???????_1889476041706625158356题干如下

07a865c9583b4f5c935a56ead47ccce8.png

当我们拿到这样的题目时的第一反应便是,将左旋的元素看作是一个部分,而将不改变的元素又视作另一个部分,在这二者独立的两个拆分的部分建立联系,并以此大做文章。

二、代码

各位看官,容我先卖个关子,我们先来思考一下,主函数里我们应该传递哪些形参变量过去呢,

有人会想,不容置喙地肯定传数组过去,没错!数组是必须的。数组长度,数组长度也应该要有,要靠数组长度控制循环啊!是的,很中肯,数组长度不可或缺。哎!还有左移的位数k,这个肯定会有的,是的没错,不过这回只说对了一半。不妨,我们先来看一个图。

7040aac233254f09b2eaeeecf07dc1d2.png

我们不难发现当以"ABCD"为例,设len 为数组长度,循环k  次,和循环k % len次的效果是一致的,因此,不妨定义一个变量time=k %  len来表示循环次数。

主函数部分代码如下:

int main()
{
	char str[]="ABCD";
	int k=0;
	scanf("%d",&k);
	int len=strlen(str);
	int time=k%len;
	LeftRound(str,time,len);
	puts(str);
	return 0;
}

一、双数组法

代码如下:

void LeftRound(char* str,int time,int len)
{
	char tmp[10];
	strcpy(tmp,str);
	for(int i=time;i<len;i++)
		str[i-time]=tmp[i];
	for(int i=0;i<time;i++)	
		str[i+len-time]=tmp[i];
}

基本思路:

用  strcpy()复制出一个临时数组 tmp[ ],这是tmp[ ]数组和str[ ]数组内的内容一致,以第 k个元素为界,然后将左旋的元素看作是一个部分,而将不改变的元素又视作另一个部分,用tmp[ ]数组分别进行循环,并赋值数组str[ ],为了方便理解我们来看一个草图。

d7050bc0751e44cd9dde458d5ae2a35a.jpeg

二、逐个挪动法

代码如下:

void LeftRound(char* str,int time,int len)
{
	for(int i=0;i<time;i++)
	{
		int j=0;
		char tmp=*str;
		for(j=0;j<len-1;j++)
		{
			str[j]=str[j+1];	
		}
		str[j]=tmp;
	}
}

基本思路:

外层循环 i 控制循环次数,内层循环 j 控制数组内字符的移动,每次循环时 ,将数组的第一个元素赋值给临时变量 tmp ,然后内层循环使.得每一个数组往前移动填补空缺。在结束循环时,将原先赋给 tmp 的元素,还给数组并处在最后一个,这每次内层循环结束就完成了,一个元素左旋的任务。不过值得注意的是,在内层循环中,因为第一个元素没有参与循环。所以,只有len - 1个元素,结束循环的条件是,j < len -1。而不是我们熟悉的 j < len,防止造成数组越界。

三、三步旋转法

不过与上面不同,在我们写函数之前要写一个用于数组逆置的方法。

代码如下:

void Reverse(char* str,int start,int end)
{
	while(start<end)
	{
		char tmp=str[start];
		str[start]=str[end];
		str[end]=tmp;
		start++;
		end--;
	}
}

基本思路:

首先,我们除了数组之外我们还需要明确从哪里开始逆置,又在哪里结束逆置。因此,我们需要形参变量,起始下标 start ,和结束下标 end。在完成一次互换之后,start++,end--,使两个下标逐渐靠近,直到 start=end 结束循环同时完成逆置。

明确这个,我们来想一想如何实现函数呢?不妨我们再来看一个图。

e8b7aa194851447b85ffd39e9119b8be.png

先将第0个到第time -1 个元素逆置,再将第time 个到 len-1逆置,再整体完成逆置,结果就是我们所想要的结果。

代码如下:

void LeftRound(char* str,int time,int len )
{
	Reverse(str,0,time-1);
	Reverse(str,time,len-1);
	Reverse(str,0,len-1);
}

四、库函数法

代码如下:

void LeftRound(char* str,int time ,int len)
{
	char tmp[10];
	strcpy(tmp,str+time);
	strncat(tmp,str,time);
	strcpy(str,tmp);
}

要读懂这几行代码,我们先对相关库函数做一个简单的了解。

strcpy( )

C语言函数

原型声明:

char *strcpy(char* dest, const char *src);

头文件:#include <string.h> 和 #include <stdio.h>

功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间

说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

返回指向dest的指针

strnact( )

C语言函数

原型声明:

char * strncat(char *dest, const char *src, size_t n);

头文件:#include <string.h> 和 #include <stdio.h>

主要功能是在字符串的结尾追加n个字符。
基本思路:

明确此我们再来回看那段代码:

void LeftRound(char* str,int time ,int len)
{
	char tmp[10];
	strcpy(tmp,str+time);
	strncat(tmp,str,time);
	strcpy(str,tmp);
}

因为,strcpy( )的作用是以地址媒介开始复制到另一个数组。因此,不妨将直接将第 k 个元素的地址传过去,这样第 k 个到第 len 个就储存在tmp[ ] 数组里。然后,再使用strncat( ),将前 k 个元素连接到tmp[ ]数组上,这样就完成了左旋要求。不过这时,数据存放在 tmp[ ]数组中,最后使用strcpy( ),将元素返回str[ ]数组中,这样便完成了数组左旋的要求。

  • 32
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值