news 2026/10/9 2:54:35

LeetCode 189. 轮转数组:从直观模拟到最优原地算法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 189. 轮转数组:从直观模拟到最优原地算法

1. 题目描述(题目链接):

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

示例:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]

2. 方法一:辅助数组法

核心思想是:开辟一个新的数组,将原数组中的每个元素直接放到它最终应该在的位置上。

核心公式推导:

对于原数组下标为 i 的元素,向右轮转 k 位后,它的新下标 new_index 为:new_index = (i + k) % n (其中 n 为数组长度)

class Solution { public: void rotate(vector<int>& nums, int k) { int n = nums.size(); vector<int> nums2(n); // 将每个元素直接放到最终位置 for (int i = 0; i < n; i++) { nums2[(i + k) % n] = nums[i]; } // 将新数组拷贝回原数组 nums = nums2; } };

复杂度分析:

时间复杂度: O(N),遍历一次数组。

空间复杂度: O(N),需要创建一个与原数组等大的新数组。

3. 方法二:三次翻转法(最优解)

这是本题在面试中最受青睐的解法。

核心思路:

向右轮转 k 位,本质上就是将数组的后 k 个元素移动到前面。我们可以通过以下三步实现:

  1. 整体翻转:将整个数组翻转。此时,原本在末尾的 k 个元素跑到了数组的最前面
  2. 翻转前 k 个元素:将这 k 个元素恢复顺序。
  3. 翻转剩余的 n-k 个元素:将剩余元素恢复顺序。

演示:

假设 nums = [1,2,3,4,5,6,7], k = 3

  1. 整体翻转 [1,2,3,4,5,6,7] -> [7,6,5,4,3,2,1]
  2. 翻转前 k 个 (前3个) [7,6,5] -> [5,6,7]。数组变为:[5,6,7,4,3,2,1]
  3. 翻转剩余部分 (后4个) [4,3,2,1] -> [1,2,3,4]。数组变为:[5,6,7,1,2,3,4] (完成)

注意: 如果 k 大于数组长度,需要先进行 k = k % n 取余操作,因为轮转 n 次等于没轮转。

代码实现 (C++):

class Solution { public: void rotate(vector<int>& nums, int k) { int n = nums.size(); k = k % n; // 处理 k > n 的情况 // 使用 C++ STL 的 reverse 函数 reverse(nums.begin(), nums.end()); // 1. 整体翻转 reverse(nums.begin(), nums.begin() + k); // 2. 翻转前 k 个 reverse(nums.begin() + k, nums.end()); // 3. 翻转剩余部分 } };

复杂度分析:

时间复杂度:ON,每个元素被翻转了两次。

空间复杂度:O1,原地修改,不需要额外空间。

4. 方法三:环形替换法(原地算法)

这也是一种O(1)空间的原地算法,但逻辑比三次翻转法更复杂。

核心思路:

我们可以直接把每个元素放到它最终的位置上。如果我们从下标 0 开始,将 nums[0] 移动到 (0+k)%n,然后继续移动被覆盖的元素,我们会形成一个闭环。

但是,如果 n 和 k 的最大公约数大于 1,我们会在回到起点时,还有元素没有移动。因此,我们需要从下一个下标开始,继续这个过程,直到所有元素都被移动。

代码实现:

class Solution { public: void rotate(vector<int>& nums, int k) { int n = nums.size(); k = k % n; int count = 0; // 记录已移动的元素个数 // 当已移动元素数小于 n 时继续 for (int start = 0; count < n; start++) { int current = start; int prev = nums[start]; do { // 计算下一个位置 int next = (current + k) % n; // 暂存下一个位置的值,并将 prev 放入 swap(nums[next], prev); // 移动到下一个位置 current = next; count++; } while (start != current); // 形成闭环后退出 } } };

复杂度分析:

时间复杂度: O(N),每个元素只被访问和移动一次。

空间复杂度: O(1)。

5. 总结

算法名称

时间复杂度

空间复杂度

辅助数组法

O(N)

O(N)

三次翻转法

O(N)

O(1)

环形替换法

O(N)

O(1)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 2:53:52

【基础IO】-1-预备知识与准备工作

预备1 > 对文件操作&#xff0c;本质是IO2 > 文件的组成3 > 打开文件3.1、“打开”的本质3.2、为什么要打开文件3.3、“谁”来打开文件4 > 文件与系统调用总结现在我们进入了Linux中的“文件”部分。 我们先从“基础IO”说起。要学习“基础IO”&#xff0c;我们就…

作者头像 李华
网站建设 2026/10/9 2:52:52

02_股票量化数据获取与质量保障体系:从 Tushare 到本地高可用存储

02_股票量化数据获取与质量保障体系&#xff1a;从 Tushare 到本地高可用存储数据是量化交易的基础。本文深入剖析 GPFX 系统如何构建一套完整的股票数据获取、校验、存储、清理体系&#xff0c;涵盖 Tushare API 封装、数据质量校验、复权计算、滚动窗口清理等核心技术&#x…

作者头像 李华
网站建设 2026/10/9 2:52:45

分布式事务问题的种常见解决方案《第六章》

在微服务架构与分布式系统盛行的今天&#xff0c;数据一致性问题成为开发者必须直面的核心挑战。传统的本地事务&#xff08;ACID&#xff09;在跨服务、跨数据库的场景下显得力不从心&#xff0c;分布式事务应运而生。本文将从实战角度出发&#xff0c;深入剖析6种主流的分布式…

作者头像 李华
网站建设 2026/10/9 2:52:41

登山杖分析

计划徒步&#xff0c;把登山杖拿出来检查下&#xff0c;取出来掉了一段&#xff0c;以为内部线断了坏了。想着顺手拆了看看&#xff0c;在观察它结构过程中&#xff0c;反而给它修好了。杖尖杖尖是六角星纹理&#xff0c;增加摩擦力抓地&#xff0c;通常是硬度较高的材料。杖尖…

作者头像 李华
网站建设 2026/10/9 2:52:06

新手快速上手 Okbiye|毕设一站式辅助平台入门指南✨

第一次使用 Okbiye 不知道从哪里开始&#xff1f;本篇为新手准备完整入门流程&#xff0c;从注册新建项目&#xff0c;到依次完成开题、文献研读、写作润色、绘图、排版、答辩 PPT&#xff0c;一步一步带你上手整套平台功能。 一、前期准备工作 打开 Okbiye 官网&#xff0c;登…

作者头像 李华
网站建设 2026/10/9 2:51:49

SSH 常见用法(三):SSH 隧道与端口转发

SSH 常见用法&#xff08;三&#xff09;&#xff1a;本地端口转发与远程端口转发 系列导读 本系列共包含一篇总览和四篇专题文章&#xff1a; 系列位置文章主题主要内容总览浅谈 SSH&#xff1a;原理、认证与四种常见用法认识 SSH 及其四种常见用法第一篇SSH 常见用法&…

作者头像 李华