leetcode
在有序数组中实现原地右旋操作,可以通过三次翻转法高效完成。以下是详细实现方法及代码解析:
核心思路:三次翻转法
- 整体翻转:将数组所有元素顺序颠倒,使末尾元素前置。
- 前k部分翻转:对前k个元素再次翻转,恢复其原有顺序。
- 剩余部分翻转:对剩余元素翻转,恢复原有顺序。
Go 代码实现
func rotate(nums []int, k int) {n := len(nums)if n <= 1 || k == 0 {return}k %= n // 处理k大于数组长度的情况[1,6](@ref)// 自定义翻转函数reverse := func(arr []int, start, end int) {for start < end {arr[start], arr[end] = arr[end], arr[start]start++end--}}reverse(nums, 0, n-1) // 整体翻转reverse(nums, 0, k-1) // 前k个元素翻转reverse(nums, k, n-1) // 剩余元素翻转 }
代码解析
-
边界处理:
- 当数组长度 ≤1 或
k=0
时直接返回,无需操作。 k %= n
确保有效旋转次数(如nums=[1,2], k=3
等效于k=1
)。
- 当数组长度 ≤1 或
-
翻转逻辑:
- 整体翻转:将
[1,2,3,4,5,6,7]
变为[7,6,5,4,3,2,1]
。 - 前k部分翻转:取前k=3个元素
[7,6,5]
翻转成[5,6,7]
。 - 剩余部分翻转:剩余元素
[4,3,2,1]
翻转成[1,2,3,4]
,最终得到[5,6,7,1,2,3,4]。
- 整体翻转:将
-
时间复杂度:
- O(n),每个元素被翻转两次(整体翻转两次,部分翻转两次)。
-
空间复杂度:
- O(1),仅使用双指针变量。
示例验证
-
输入:
nums = [1,2,3,4,5,6,7], k=3
- 整体翻转 →
[7,6,5,4,3,2,1]
- 前3个翻转 →
[5,6,7,4,3,2,1]
- 剩余部分翻转 →
[5,6,7,1,2,3,4]
- 整体翻转 →
-
输入:
nums = [-1,-100,3,99], k=2
- 整体翻转 →
[99,3,-100,-1]
- 前2个翻转 →
[3,99,-100,-1]
- 剩余部分翻转 →
[3,99,-1,-100]
- 整体翻转 →
扩展方法对比
方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
三次翻转法 | O(n) | O(1) | 原地操作,推荐使用 |
环状替换法 | O(n) | O(1) | 数学逻辑复杂 |
额外数组法 | O(n) | O(n) | 非原地操作,逻辑简单 |
注意事项
- 切片操作边界:Go语言中
nums[:k]
包含第0到k-1个元素,需确保索引正确。 - 大数优化:
k %= n
避免无效旋转(如k=1e5
而n=7
时等效于k=5
)。
该方法通过三次翻转实现高效原地旋转,是LeetCode经典题目的标准解法,综合了时间与空间的最优平衡。