旋转数组的四种解法

示例:给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例:
输入: [1,2,3,4,5,6,7] 和 k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]

解法1:遍历法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lvbgoAGY-1607222582345)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201206093553447.png)]

void rotate(int* nums, int numsSize, int k){
	for (int i = 0; i<k; i++)
	{
		int previous = nums[numsSize - 1];
		for (int j = 0; j<numsSize; j++)
		{
			int temp = nums[j];
			nums[j] = previous;
			previous = temp;
		}
	}

}

解法2:反转法

在这里插入图片描述

void Reverse(int arr[], int left, int right)
{
	while (left<right)
	{
		int temp = arr[left];
		arr[left] = arr[right];
		arr[right] = temp;
		left++;
		right--;
	}
}

void rotate(int* nums, int numsSize, int k){
	k %= numsSize;//K=numsSize即一个完整循环相当于没有移动
	Reverse(nums, 0, numsSize - 1);//完成整体反转
	Reverse(nums, 0, k - 1);//完成前半部分反转
	Reverse(nums, k, numsSize - 1);//完成后半部分反转
}

解法3:开辟数组法

开辟一个新的动态数组,将尾端往前K个位置开始,将原数组中的元素拷贝到新数组中,在将前半部分拷贝过去,
这样就完成了数组的旋转,最后只需将内容拷贝回原数组;

void rotate(int* nums, int numsSize, int k)
{
	k %= numsSize;
	int *arr = (int *)malloc(sizeof(int)*numsSize);
	int count = 0;
	for (int i=numsSize-k; i < numsSize; i++)
	{
		arr[count] = nums[i];//将需要颠倒的先拷贝过去
		count++;
	}
	for (int j = 0; j< numsSize - k; j++)
	{
		arr[count] = nums[j];//再将后面的拷贝过来
		count++;
	}
	for (int j = 0; j < numsSize; j++)

	{
		nums[j] = arr[j];//拷贝回原数组
	}
}

解法4:环状替换法

环状替换法,即从起点开始,每次以K为单位进行跳跃式的替换,每个元素都会进行一次替换,进行了N次替换,即完成了数组的旋转;
注意点:
1.当下标+K大于数组长度的时候,就需要减去长度回到”起点“处;
2.回到起点后,判断回来的位置是否和出发的位置重复,如果不重复,那么一直进行下去,直至完成N此跳跃,形成一个环圈;
如果重合了,每次回到起点后就将起点完后挪动一个位置,直至完成N次跳跃;

在这里插入图片描述

void rotate(int* nums, int numsSize, int k){
	k %= numsSize;
	int count = 0;
	int previous = nums[0];//先将出发点元素储存起来,和遍历法类似
	int lable = 0;//标记出发点,用于判断返回点是否和出发点重合
	int sub = k;
	while (count < numsSize)//count=元素个数时跳出循环,即完成了size次交换
	{
		if (sub < numsSize)//跳跃之后没有超过数组长度
		{
			int temp = nums[sub];
			nums[sub] = previous;//进行替换
			count++;
			previous = temp;
			sub += k;//跳跃K个距离
		}
		else//即将完成一个系列的转换
		{
			int temp = nums[sub - numsSize];//超过了数组长度,回到起点
			nums[sub - numsSize] = previous;
			count++;
			previous = temp;
			if (sub - numsSize == lable)//回到起点的位置和出发位置相同
			{
				sub = sub - numsSize + 1;
				lable = sub;//继续标记出发位置
				previous = nums[sub];//重新储存起点
				sub += k;
			}
			else
			{
				sub = sub - numsSize + k;
			}
			
		}
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值