数组——旋转数组

题目:给一个数组,和长度,还有一个k值,将数组后移k个位置。注意:超过最后的位置的数组,会循环到第一个位置。
例如:arr[7] = {1,2,3,4,5,6,7}; len = 7; k = 3;
旋转过后数组为:arr[7] = {5,6,7,1,2,3,4};
首先k = k%len;k和k = k%len效果一样。比如上面例子,移7位和移0位一样,优化一下,k = %len。

本篇博客记录以下几种方法:
1.将最后一个元素拿出来保存到tmp中,其他元素都后移k个,将tmp赋值给第一个元素。重复操作k次即相当于每个元素都后移k个位置。
2.直接在原数组上交换,从arr[0]开始,找arr[0]的移动后的位置,将该位置的值和下标保存下来,将arr[0]放进去,然后找该位置本来的值的移动后的位置。交换len次即可。
3.整个数组逆置,再将前半部分和后半部分逆置。
4.找到下标移动后对应的下标,配合空间使用。

一、一次将元素移动一个单元格,操作k次

//将最后一个元素存放到tmp中,前面的元素向后移一个位置,重复k次操作。最后一个元素后移一位即放到第一个元素位置上
void move_one(int* arr, int len)//每个元素后移一位
{
	int tmp = arr[len - 1];//保存最后一个元素
	for (int i = len - 2; i >= 0; i--)//每个元素都向后移一个单元格
	{
		arr[i + 1] = arr[i];
	}
	arr[0] = tmp;//将原本的最后一个元素放到第一个位置上
}

void Reversal_arr_1(int* arr, int len, int k)
{
	assert(arr != NULL);
	k = k % len;

	for (int i = 1; i <= k; i++)//一次移一位,操作k次即移动k位
	{
		move_one(arr, len);
	}
}

二、直接在原数组上交换,将被交换掉的元素再和其他元素交换

思路:如下图
在这里插入图片描述
代码:

//直接一个一个元素的找对应的位置,被替换掉的元素用tmp保存,找被替换掉的元素的位置
void Reversal_arr_2(int* arr, int len, int k)//k = 2
{
	assert(arr != NULL);
	k = k % len;

	int tmp = 0;     //保存要被覆盖的值
	int index = 0;   //保存要被覆盖的值的下标
	int cur = arr[0];//保存下一个要移动的值

	for (int i = 1; i <= len; i++)//len个元素,总共找len次位置就可以了
	{
		tmp = arr[(index + k) % len];//先保存即将被替换掉的值
		arr[(index + k) % len] = cur;  //找到cur元素移动后的位置,放进去
		index = (index + k) % len;     //下一次将要移动的元素的下标(即cur替换掉的元素的下标)
		cur = tmp;                              //下一次将要移动的元素的值(即被cur覆盖掉的值)
	}
}

三、整个数组逆置,再将前半部分和后半部分逆置

思路:{1,2,3,4,5,6,7}移动3个单元格时,{5,6,7}变成前三个元素,{1,2,3,4}变成后四个元素。
第一步:{1,2,3,4,5,6,7}
整个数组逆置后:{7,6,5,4,3,2,1}
发现567和1234分别在数组的前三个和后四个
**第二步:**将前3个再逆置,将后四个再逆置
{5,6,7,1,2,3,4}
完成。
代码:

//整个数组的元素逆置,然后将前k个元素逆置,将后len-k个元素逆置
void Reversal_arr(int* arr, int start, int last)//将数组的下标为[start,last]的元素逆置
{
	assert(arr != NULL && start <= last);
	
	int i = start;
	int j = last;
	while (i < j)
	{
		swap(arr[i++], arr[j--]);
	}
}

void Reversal_arr_3(int* arr, int len, int k)//k = 2
{
	assert(arr != NULL);
	k = k % len;
	
	Reversal_arr(arr, 0, len - 1);//全部逆置
	Reversal_arr(arr, 0, k - 1);  //前k个逆置
	Reversal_arr(arr, k, len - 1);//后len-k个逆置
}

四、直接找下标移动后对应的下标

思路:直接找下标移动后对应的下标,和第二个方法一样,只不过第二个方法由于会产生覆盖问题,所以下一个移动的元素就是上一个被覆盖的元素,是跳着移动元素。
只不过这里是从前向后一个一个元素的移动,如果直接在原数组中操作,后面多个元素被覆盖,所以这里借助辅助空间,都移动到辅助空间中,再拷贝到arr中。这个方法没有第二个方法好。第二个方法只用了三个多余变量,这个方法用了一个数组。空间复杂度为O(n)。
代码:

void Reversal_arr_4(int* arr, int len, int k)
{
	assert(arr != NULL);
	k = k % len;

	int* newdata = (int*)malloc(sizeof(int) * len);
	assert(newdata != NULL);

	for (int i = 0; i < len; i++)
	{
		newdata[(i + k) % len] = arr[i];
	}
	memcpy(arr, newdata, sizeof(int) * len);
	delete newdata;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟小胖_H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值