【经典算法】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
相关推荐
KiddoStone2 分钟前
多实例schedule job同步数据流的数据一致性设计和实现方案
java
我爱C编程15 分钟前
基于拓扑结构检测的LDPC稀疏校验矩阵高阶环检测算法matlab仿真
算法·matlab·矩阵·ldpc·环检测
算法_小学生20 分钟前
LeetCode 75. 颜色分类(荷兰国旗问题)
算法·leetcode·职场和发展
运器12323 分钟前
【一起来学AI大模型】算法核心:数组/哈希表/树/排序/动态规划(LeetCode精练)
开发语言·人工智能·python·算法·ai·散列表·ai编程
算法_小学生23 分钟前
LeetCode 287. 寻找重复数(不修改数组 + O(1) 空间)
数据结构·算法·leetcode
岁忧24 分钟前
(LeetCode 每日一题) 1865. 找出和为指定值的下标对 (哈希表)
java·c++·算法·leetcode·go·散列表
alphaTao24 分钟前
LeetCode 每日一题 2025/6/30-2025/7/6
算法·leetcode·职场和发展
ゞ 正在缓冲99%…24 分钟前
leetcode67.二进制求和
算法·leetcode·位运算
YuTaoShao27 分钟前
【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法
java·算法·leetcode
写个博客1 小时前
暑假算法日记第二天
算法