【经典算法】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
相关推荐
码流子26 分钟前
移动收费怎么做?手持终端+App+收费中心的架构实践
java·开发语言·架构
霸道流氓气质40 分钟前
AI 流式对话与实时聊天平台:SSE 解码竞态、有状态会话隔离与背压取消的 Vue3 + Spring AI 生产级实战
java·人工智能·spring
夜不会漫长1 小时前
C++:红黑树
数据结构·算法
云创智城-yuncitys1 小时前
YunParking 4.0:JDK 17 与 Spring Boot 3.2 的停车云升级
java·开发语言·spring boot
文丑颜不良啊1 小时前
LeetCode1661~1680题目解析
java·leetcode
子非鱼@Itfuture1 小时前
关于前后端联调中登录状态/登录信息失效?
java·前端
郭小李1 小时前
openFeign入门
java·开发语言·前端
wljt1 小时前
公司二-面试题
java·开发语言·mybatis
AI备案指南-满满1 小时前
算法备案审核不通过,一般是什么原因?
java·人工智能·算法·大模型备案·算法备案·大模型登记
Ramble_Naylor2 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust