一. 简介
本文记录力扣网上涉及数组方面的编程题,主要以 C语言实现。
二. 力扣上C语言编程题:轮转数组
给定一个整数数组 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]
进阶:
- 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
- 你可以使用空间复杂度为
O(1)
的 原地 算法解决这个问题吗?
解题思路一:(普通解法一) 重新开辟缓存,并拷贝
注意:本题需要考虑特殊情况,当轮转次数 k 大于数组元素个数 numsSize的情况:k = k%numsSize。如果不处理,则在后面 numsSize-k可能会是负数,会导致数组越界!!!
(1) 对 k> numsSize的情况 进行处理,k = k % numsSize;
(2) 开辟一段临时缓存,将后面的数组元素先拷贝到数组前面,再将数组前的 (numsSize-k)个元素拷贝到该缓存后面;
(3) 将最新缓存中元素全部拷贝到原来数组中(申请的堆用完后必须释放,否则会引起内存泄漏);
C语言实现如下:
#include <stdio.h>
#include <stdlib.h>
void rotate(int* nums, int numsSize, int k) {
if((!nums) || (numsSize == 0)) {
return;
}
//考虑当轮转次数 > 数组元素个数时的情况
if(k > numsSize) {
k = k % numsSize;
}
int* tmp_ptr = (int*)malloc(numsSize * sizeof(int));
if(NULL == tmp_ptr) {
printf("ptr malloc failed!\n");
return;
}
int m = numsSize - k;
memcpy(tmp_ptr, &nums[m], k*sizeof(int));
memcpy(&tmp_ptr[k], nums, m*sizeof(int));
memcpy(nums, tmp_ptr, numsSize*sizeof(int));
free(tmp_ptr);
tmp_ptr = NULL;
}
可以看到,这个解法的时间复杂度为 O(n),空间复杂度为O(n)。
解题思路二:(普通解法二)找到原数组元素索引与新数组元素索引的关系:
new_nums[(i + k) % numsSize] = nums[i]
具体方法:
1. 首先申请一段内存,遍历数组,将原数组元素放到最新位置(新数组中);
2. 再将新数组中的元素逐个放到原数组中;
C语言实现如下:
//普通解法二
//原数组元素的索引与新数组元素索引的对应关系
//new_nums[(i+k)%numsSize] = nums[i]
void rotate(int* nums, int numsSize, int k) {
int i;
int new_nums[numsSize];
//遍历数组,将原数组中元素放到新位置
for(i = 0; i < numsSize; i++) {
new_nums[(i+k)%numsSize] = nums[i];
}
//再将新数组中元素逐个赋值给原数组中
for(i = 0; i < numsSize; i++) {
nums[i] = new_nums[i];
}
}
解题思路三:三次逆序法
具体思路:
1. 首先,将前面 numsSize-k 个元素逆序;
2. 其次,将数组的后 k个元素逆序;
3.最后,将整体逆序;
C语言实现如下:
//三次轮转(双指针)
void reserve_element(int* nums, int left, int right) {
while(left < right) {
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
left++;
right--;
}
}
void rotate(int* nums, int numsSize, int k) {
//首先处理特殊情况(这里必须要处理)
if(k > numsSize){
k = k % numsSize;
}
//整个数组中所有元素进行轮转
reserve_element(nums, 0, numsSize-1);
//轮转前面 k个元素
reserve_element(nums, 0, k-1);
//最后轮转后面 n-k个元素
reserve_element(nums, k, numsSize-1);
}
可以看出,这个解法满足进阶要求,算法空间复杂度为O(1)。
注意:必须对 k > numsSize的特殊情况进行处理,两次我都忽略了!!!