LeetCode 189 轮转数组

1. 题目

189. 轮转数组 - 力扣(LeetCode)

题目描述

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

要求尽可能想出多种实现方案,至少满足空间 O (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

输入:nums = -1,-100,3,99, k = 2

输出:3,99,-1,-100

约束

  • (1 <= nums.length <= 10^5)

  • (-2^{31} <= numsi <= 2^{31}-1)

  • (0 <= k <= 10^9)

2. 最佳解题思路描述(三次反转法,原地最优)

核心原理

数组右移 k 位等价于:把后 k 个元素挪到数组前面。利用反转分段实现,三步操作:

  1. 对整个数组全部反转;

  2. 反转前 k 个元素;

  3. 反转剩下 n-k 个元素。

前置关键:

k %= n 取模压缩,消除 k ≥ 数组长度的无效旋转(旋转 n 次等于原数组不变)。

举例 nums=1,2,3,4,5,6,7,k=3,n=7

  1. 整体反转:7,6,5,4,3,2,1

  2. 反转前 3 个:5,6,7,4,3,2,1

  3. 反转后 4 个:5,6,7,1,2,3,4

优势

  • 时间复杂度 (O(n)),每个元素仅被反转 2 次;

  • 空间复杂度 (O(1)),完全原地修改,不新开数组;

  • 代码极简,标准面试最优解。

3. 我的可优化代码(无逻辑错误,标准最优,仅补充说明细节)

复制代码
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k %= n;
        reverse(nums.begin(), nums.end());
        reverse(nums.begin(), nums.begin() + k);
        reverse(nums.begin() + k, nums.end());
    }
};

代码说明

  1. 正确性:逻辑无任何 bug,可通过全部测试用例,是官方推荐最优写法;

  2. 关键点不能省略:

    • k %= n:k 极大时避免无效循环,例如 n=3,k=1000,实际只需右移 1 次;

    • 三次 reverse 顺序固定,调换顺序结果错误;

  3. 小拓展:如果题目要求向左轮转 k 位,可调整反转分段逻辑。

4. 标准规范完整代码(带上头文件说明)

复制代码
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k = k % n;
        // 整体反转
        reverse(nums.begin(), nums.end());
        // 反转前k段
        reverse(nums.begin(), nums.begin() + k);
        // 反转剩余后段
        reverse(nums.begin() + k, nums.end());
    }
};

5. 总结

  1. 三次反转是本题空间 O (1) 最优模板,代码简洁、效率高,面试首选;

  2. 固定三步口诀:全反转 → 前 k 反转 → 后段反转;

  3. 必须先对 k 取模,否则大数 k 无意义;

  4. 原地类旋转数组优先考虑分段反转思想。

6. 相关知识拓展

拓展 1:额外数组辅助法(空间 O (n),思路简单但不推荐面试)

新建数组存储后 k 位 + 前 n-k 位,再拷贝回原数组:

复制代码
void rotate(vector<int>& nums, int k) {
    int n = nums.size();
    k %= n;
    vector<int> tmp;
    for(int i = n - k; i < n; i++) tmp.push_back(nums[i]);
    for(int i = 0; i < n - k; i++) tmp.push_back(nums[i]);
    nums.swap(tmp);
}

缺点:占用额外数组空间,不符合原地要求。

拓展 2:循环交换法(原地 O (1),逻辑复杂)

从下标 0 开始,每次把元素放到目标旋转位置,记录替换次数,直到全部元素归位,无需反转,但需要额外变量记录中间值,代码可读性差。

拓展 3:反转模板通用场景

数组分段交换、字符串旋转、字符串左移 / 右移均可使用分段反转思想;

例如字符串左旋:abcdefg 左旋 2 位得到 cdefgab,同样用三段反转实现。

拓展 4:复杂度对比

  1. 三次反转原地法:时间 (O(n)),空间 (O(1))(最优);

  2. 辅助数组拷贝:时间 (O(n)),空间 (O(n));

  3. 循环逐个移动暴力法:时间 (O(nk)),大数据超时,完全不推荐。

相关推荐
l12586536 分钟前
# LangGraph Deep Research Agent 全流程设计:多轮研究、人机协同与真实来源管理
数据库·人工智能·python·算法·自然语言处理·oracle·langchain
青少儿编程课堂1 小时前
图形化编程实战:智能交通灯调度台,一个作品讲透循环、条件与广播
c++·python·算法·bfs·信息学竞赛
evans在进步1 小时前
LeetCode 438 找到字符串中所有字母异位词:滑动窗口与排序解法详解
算法·leetcode·职场和发展
M78佐菲1 小时前
Linux多线程:创建、回收与互斥同步
linux·笔记·学习·算法
小手cool1 小时前
使用递归对数组进行反转操作
java·数据结构·算法
兔兔兔兔12 小时前
记录C++ 13
开发语言·c++·算法
码行山野赴时序归途2 小时前
从暴力到最优:三道 C 语言入门题的解法思路
c语言·开发语言·数据结构·算法·leetcode·排序算法
土司大王2 小时前
LeetCode hot100——随机链表的复制
算法·leetcode·链表
叠层归一研究院2 小时前
螺旋时空:E框架的整合宇宙论
人工智能·经验分享·算法·机器学习·agi
磁场转动100万匹2 小时前
线性回归算法实现训练数据集、测试数据集的缺失值填充
算法·机器学习·线性回归