轮转数组的三种解法

先看题目

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [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]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

解法一:暴力求解

1.把数组最后一个数存起来

2.数组整体后移

3.把这个数放到数组第一个

上代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//暴力求解
void reverse(int nums[],int n,int k)
{
	while (k--)
	{
		//把数组最后一个数存起来
		int tmp = nums[n - 1];
		//数组整体后移
		int i = 0;
		for (i = n - 1; i > 0; i--)
		{
			nums[i] = nums[i - 1];
		}
		//把这个数放到数组第一个
		nums[0] = tmp;
	}
}
int main()
{
	int nums[] = { 1,2,3,4,5,6,7 };
	int k = 3;
	int numsSize = sizeof(nums) / sizeof(nums[0]);
	reverse(nums, numsSize,k);
	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		printf("%d ", nums[i]);
	}
	return 0;
}

 这种方法是最容易想到的方法,但是面对一些对复杂度有要求的题,这种方法是不行的。

时间复杂度:O(N^2)

空间复杂度:O(1)

解法二:空间换时间

1.新建一临时数组

2.先拷贝后k个元素

3.再拷贝前n-k个元素

4.用新建数组覆盖原数组

上代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//空间换时间
void reverse(int* nums, int n, int k)
{
	//1.动态开辟临时数组
	int* tmp = (int*)malloc(sizeof(int) * n);
	//2.把原数组后k个,拷贝到新数组
	memcpy(tmp, nums + n - k, sizeof(int) * (k));
	//3.再把原数组前n-k个,拷贝到新数组
	memcpy(tmp + k, nums, sizeof(int) * (n - k));
	//4.用新建数组覆盖原数组
	memcpy(nums, tmp, sizeof(int) * n);

	free(tmp);
	tmp = NULL;
}

int main()
{
	int nums[] = { 1,2,3,4,5,6,7 };
	int k = 3;
	int numsSize = sizeof(nums) / sizeof(nums[0]);
	k %= numsSize;
	reverse(nums, numsSize, k);

	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		printf("%d ", nums[i]);
	}
	return 0;
}

时间复杂度:O(N)

空间复杂度:O(N)

解法三:三段逆置

这是可以说是找规律,也可以说使用数学思维解决问题

1.前n-k个逆置

原来:1 2 3 4 5 6 7

逆置:4 3 2 1 5 6 7

2.后k个逆置

原来:4 3 2 1 5 6 7

逆置:4 3 2 1 7 6 5

3.整体逆置

原来:4 3 2 1 7 6 5

逆置:5 6 7 1 2 3 4

上代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

reverse(int* a, int left, int right)
{
	while (left < right)
	{
		int tmp = a[left];
		a[left] = a[right];
		a[right] = tmp;

		++left;
		--right;
	}
}

int main()
{
	int nums[] = { 1,2,3,4,5,6,7 };
	int k = 3;
	int numsSize = sizeof(nums) / sizeof(nums[0]);
	k %= numsSize;
    
	reverse(nums, 0, numsSize - k-1);
	reverse(nums, numsSize - k, numsSize-1);
	reverse(nums, 0, numsSize-1);

	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		printf("%d ", nums[i]);
	}
	return 0;
}

时间复杂度:O(N)

空间复杂度:O(1)

下标非常易错

	reverse(nums, 0, numsSize - k-1);
	reverse(nums, numsSize - k, numsSize-1);
	reverse(nums, 0, numsSize-1);
	memcpy(tmp, nums + numsSize - k, sizeof(int) * (k));
	memcpy(tmp + k, nums, sizeof(int) * (numsSize - k));
	memcpy(nums,tmp, sizeof(int) * numsSize);

画图来帮助理解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值