力扣网编程189题:轮转数组(中等)

一. 简介

本文记录力扣网上涉及数组方面的编程题,主要以 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的特殊情况进行处理,两次我都忽略了!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值