目录
题目描述
给定一个整数数组 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]
一、暴力求解法
之所以叫暴力求解法,是因为此法一上来就直接按要求旋转,毫不“拖泥带水”,但此法真的高效吗?通过计算,会得到该算法的时间复杂度为O(n^2),显然是比较低效率的。下面还是看看它如何实现吧。空间复杂度为O(1)。
这里先说只旋转一个数字的方法,因为旋转多个数字可以拆分为多次只旋转一个数。
第一步:记住首元素
第二步:将后面的元素依次向前覆盖
第三部:将首元素放入数组中的最后一个位置
请看代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void reverse(int arr[], int len, int k);//声明
void print(int arr[], int len);//声明
int main()
{
int arr[] = { 1,2,3,4,5,6,7 };
int len = sizeof(arr) / sizeof(arr[0]);
int k = 0;//旋转的个数
scanf("%d", &k);
reverse(arr, len, k);//旋转函数
print(arr, len);//打印函数
return 0;
}
void reverse(int arr[], int len, int k)
{
k %= len;
for (int i = 0; i < k; i++)
{
int tmp = arr[0];//保存每一次的首元素
int j = 0;
for (j = 0; j < len - 1; j++)
{
arr[j] = arr[j + 1];
}
//跳出内层for循环后j = len - 1
arr[j] = tmp;
}
}
void print(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
}
二、利用库函数
利用到的库函数是memcpy,下面介绍一下这个函数。
void *memcpy( void *dest, const void *src, size_t count );
> 可用于任意类型数据的拷贝
> 第一个参数为目标位置的地址
> 第二个参数为数据来源的地址
> 第三个参数为要拷贝的字节数
介绍完memcpy这个函数后,接下来说一说该如何拷贝。
此方法需要开辟额外的空间,可以选择用内存函数malloc来开辟,如果不了解malloc也可以选择直接创建一个与原数组等大的新数组。思想是一样的,只是开辟空间的方式不一样。这里给出创建数组的方法。
以旋转3个数字为例,n为数组元素个数,k为要旋转的元素个数。
第一步:拷贝前n-k个元素到后面的位置
第二步:拷贝要旋转的k个元素到前面位置
第三步:将新开辟空间中的数据拷贝到原数组
因为此方法额外开辟了空间,所以可以理解为此方法是用空间来换时间,时间复杂为O(N),空间复杂度为O(N)。
请看代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
void reverse(int arr[],int len,int k);
void print(int arr[], int len);
int main()
{
int arr[] = { 1,2,3,4,5,6,7 };
int len = sizeof(arr) / sizeof(arr[0]);
int k = 0;//旋转的元素个数
scanf("%d", &k);
reverse(arr, len, k);//旋转函数
print(arr, len);//打印函数
return 0;
}
void reverse(int arr[], int len, int k)
{
int tmp[7] = { 0 };
memcpy(tmp + k, arr, sizeof(int) * (len - k));//先拷贝前len - k 个
memcpy(tmp, arr + len - k, sizeof(int) * k);//再拷贝后k个
memcpy(arr, tmp, sizeof(int) * len);//z最后再整体拷贝
}
void print(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
}
三、三段逆置
时间复杂度为O(N),空间复杂度为O(1)。
第一步:先逆置前n-k个元素
第二步:再逆置后k个元素
第三步:整体逆置
请看代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
void reverse(int arr[], int len, int k);
void print(int arr[], int len);
int main()
{
int arr[] = { 1,2,3,4,5,6,7 };
int len = sizeof(arr) / sizeof(arr[0]);
int k = 0;//旋转的元素个数
scanf("%d", &k);
reverse(arr, 0, len - k -1);//先逆置前n-k个元素
reverse(arr, len - k, len - 1);//在逆置后k个元素
reverse(arr, 0, len - 1);//整体逆置
print(arr, len);//打印函数
return 0;
}
void reverse(int arr[], int left, int right)
{
while (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
void print(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
}