【经典算法】LeetCode 189. 轮转数组(Java/C/Python3/Go实现含注释说明,中等)

目录

题目描述

text 复制代码
给定一个整数数组 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 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
 

进阶:

尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?

原题:LeetCode 189

思路及实现

方式一:三次翻转

思路

将整个数组翻转,然后分别翻转前k个元素和后n-k个元素,从而达到向右轮转k个位置的效果。

代码实现

Java版本
java 复制代码
public void rotate(int[] nums, int k) {
    k %= nums.length; // 处理k大于数组长度的情况
    reverse(nums, 0, nums.length - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, nums.length - 1);
}

private void reverse(int[] nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start++;
        end--;
    }
}

// 说明:通过三次翻转实现数组的轮转,时间复杂度O(n),空间复杂度O(1)
C语言版本
c 复制代码
void reverse(int* nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start++;
        end--;
    }
}

void rotate(int* nums, int numsSize, int k){
    k %= numsSize;
    reverse(nums, 0, numsSize - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, numsSize - 1);
}

// 说明:C语言实现与Java类似,注意数组传递和指针操作
Python3版本
python 复制代码
def reverse(nums, start, end):
    while start < end:
        nums[start], nums[end] = nums[end], nums[start]
        start += 1
        end -= 1

def rotate(nums, k):
    k %= len(nums)
    reverse(nums, 0, len(nums) - 1)
    reverse(nums, 0, k - 1)
    reverse(nums, k, len(nums) - 1)

# 说明:Python版本使用切片式交换元素,实现方式与Java和C类似
Golang版本
go 复制代码
func reverse(nums []int, start, end int) {
    for start < end {
        nums[start], nums[end] = nums[end], nums[start]
        start++
        end--
    }
}

func rotate(nums []int, k int) {
    k %= len(nums)
    reverse(nums, 0, len(nums)-1)
    reverse(nums, 0, k-1)
    reverse(nums, k, len(nums)-1)
}

// 说明:Golang版本使用切片和索引操作,与Java和C的实现思路相同

复杂度分析

  • 时间复杂度:O(n),其中n是数组的长度。因为数组中的每个元素都会被翻转两到三次。
  • 空间复杂度:O(1),仅使用了常数个额外空间。

方式二:使用辅助数组

思路

使用一个与原数组大小相同的辅助数组,遍历原数组,将元素按照轮转后的位置存放到辅助数组中,最后将辅助数组的元素复制回原数组,完成轮转。

代码实现

Java版本
java 复制代码
public void rotate(int[] nums, int k) {
    k %= nums.length; // 处理k大于数组长度的情况
    int[] temp = new int[nums.length];
    for (int i = 0; i < nums.length; i++) {
        // 将元素放置到新的位置 (i + k) % nums.length
        temp[(i + k) % nums.length] = nums[i];
    }
    // 将新数组的元素复制回原数组
    System.arraycopy(temp, 0, nums, 0, nums.length);
}

// 说明:这种方式虽然使用了额外的空间,但代码逻辑较为直观,容易理解
C语言版本
c 复制代码
void rotate(int* nums, int numsSize, int k){
    k %= numsSize;
    int* temp = (int*)malloc(numsSize * sizeof(int));
    for (int i = 0; i < numsSize; i++) {
        temp[(i + k) % numsSize] = nums[i];
    }
    for (int i = 0; i < numsSize; i++) {
        nums[i] = temp[i];
    }
    free(temp); // 释放辅助数组的内存
}

// 说明:C语言需要手动管理内存,因此在使用完辅助数组后需要释放其内存
Python3版本
python 复制代码
def rotate(nums, k):
    k %= len(nums)
    temp = [0] * len(nums)
    for i in range(len(nums)):
        temp[(i + k) % len(nums)] = nums[i]
    nums[:] = temp[:]  # 将新列表的元素赋值给原列表

# 说明:Python中可以使用列表推导式或者循环来构造辅助列表,但这里为了保持与其他语言的风格一致,使用了循环
Golang版本
go 复制代码
func rotate(nums []int, k int) {
    k %= len(nums)
    temp := make([]int, len(nums))
    for i, num := range nums {
        temp[(i+k)%len(nums)] = num
    }
    copy(nums, temp) // 将新切片的元素复制回原切片
}

// 说明:Golang中使用make函数来创建切片,并使用copy函数来复制切片的内容

复杂度分析

  • 时间复杂度:O(n),其中n是数组的长度。因为需要遍历原数组一次,并将元素放置到辅助数组和复制回原数组。
  • 空间复杂度:O(n),因为使用了一个与原数组大小相同的辅助数组。

总结

方式 优点 缺点 时间复杂度 空间复杂度
方式一 空间复杂度低,仅使用常数额外空间 逻辑相对复杂,需要进行三次翻转 O(n) O(1)
方式二 逻辑直观,易于理解 需要使用额外的空间 O(n) O(n)

相似题目

相似题目 难度 链接
LeetCode 153. 寻找旋转排序数组中的最小值 中等 LeetCode
LeetCode 154. 寻找旋转排序数组中的最小值 II 困难 LeetCode
LeetCode 143. 重排链表 中等 LeetCode
相关推荐
NE_STOP11 小时前
Vide Coding--AI编程工具的选择
java
通信小呆呆11 小时前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
码云数智-园园11 小时前
C++20 Modules 模块详解
java·开发语言·spring
程序员黑豆11 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程
benben04411 小时前
强化学习之DQN算法族(基于gymnasium开发)
算法
小宇宙Zz11 小时前
Maven依赖冲突
java·服务器·maven
swordbob12 小时前
NIO的channel中什么是 fd(File Descriptor,文件描述符)
java·开发语言·nio
咖啡八杯12 小时前
GoF设计模式——享元模式
java·spring·设计模式·享元模式
十五喵源码网12 小时前
基于springboot2+vue2的租房管理系统
java·毕业设计·springboot·论文笔记