原地旋转数组的核心是三次反转,时间复杂度O(n)、空间复杂度O(1);右旋k步需全局反转、前k个反转、后n−k个反转;左旋可转为右旋n−k步;务必先k%=n并处理边界。

原地旋转数组的核心是「三次反转」,时间复杂度 O(n)、空间复杂度 O(1),比逐个移动或开新数组更优。
为什么三次反转能实现左/右旋转
以右旋 k 步为例:数组 [1,2,3,4,5] 右旋 2 步应得 [4,5,1,2,3]。直接挪动易错且难控制索引。而三次反转等价于:
① 全局反转 → [5,4,3,2,1]
② 前 k 个反转 → [4,5,3,2,1]
③ 后 n−k 个反转 → [4,5,1,2,3]。
本质是把末尾 k 段“提前”,再分别恢复两段内部顺序。
左旋只需调整反转区间:先翻前 k,再翻后 n−k,最后翻全部 —— 或更简单:右旋 n−k 步。
std::reverse 是最安全的原地反转工具
C++ 标准库提供 std::reverse,底层用迭代器交换,无越界风险,且编译器常内联优化。手写交换循环容易出 off-by-one 错误。
使用要点:
-
k必须先对数组长度取模:k = k % n,否则k > n时反转区间越界 - 空数组或
k == 0时直接返回,避免无效操作 - 反转区间用半开区间习惯:
std::reverse(begin, begin + k),不是begin + k - 1
示例(右旋):
void rotate(std::vector<int>& nums, int k) {
if (nums.empty()) return;
int n = nums.size();
k = k % n;
if (k == 0) return;
<pre class="brush:php;toolbar:false;">std::reverse(nums.begin(), nums.end());
std::reverse(nums.begin(), nums.begin() + k);
std::reverse(nums.begin() + k, nums.end());
}
手动实现反转时最容易踩的边界坑
不用 std::reverse 而手写双指针,常见错误集中在索引计算:
- 混淆左闭右闭和左闭右开:比如
for (int i = 0; i 中 <code> 在奇数长度时多换一次 - 起始位置算错:右旋
k步,前段长度是k,不是n−k;左旋才是前段为k - 未处理
k == 0或n == 1,导致nums.begin() + k越界或反转空区间崩溃
安全的手写模板(右旋):
auto rev = [&](int l, int r) {
while (l <h3>性能与兼容性注意点</h3><p>三次反转的内存访问是顺序的,缓存友好,实际比某些「环状替换」方案更快,尤其在大数组上。</p><p>但要注意:</p>
-
std::reverse要求迭代器支持双向操作,对std::list不适用(需用std::list::reverse()) - 若数组是原始指针(如
int*),需传入std::reverse(ptr, ptr + n),不能漏掉长度 - 在嵌入式或严格禁用 STL 的场景,必须手写,且务必做
n == 0和k == 0的短路判断
真正容易被忽略的是:旋转操作本身不改变元素值,但多次旋转叠加时,k 累积未取模会导致行为意外 —— 每次调用都该独立处理 k %= n。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











