LeetCode 面试经典 150 题:轮转数组(三次翻转法详解 + 多解法对比)

在数组类算法题中,“轮转数组” 是一道考察 “原地操作” 与 “逻辑转换” 能力的经典题目。所谓 “轮转”,是指将数组元素向右移动指定步数,且超出数组长度的元素需 “循环” 到数组开头。这道题的最优解 ——三次翻转法,能以 O (n) 时间复杂度和 O (1) 空间复杂度实现原地轮转,是面试中高频考察的高效思路。本文将从题目解读、三次翻转法原理、步骤演示,到代码实现,再到其他解法对比,帮你彻底掌握这道题的核心逻辑。

一、题目链接与题干解读

首先,你可以通过以下链接直接访问题目,先自行思考解题方向:

LeetCode 题目链接:189. 轮转数组

题干核心信息

题目要求如下:

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

例如,若 nums = [1,2,3,4,5,6,7],k = 3,则轮转后数组为 [5,6,7,1,2,3,4]。

关键注意点

  • k 的取值范围:k 可能大于数组长度 n,此时轮转效果与 “k 对 n 取模” 后的结果一致(例如 n=7,k=10,10 mod 7=3,轮转 10 步与轮转 3 步结果相同);
  • 原地操作要求:若想达到最优空间复杂度,需避免开辟新数组,在原数组上完成轮转;
  • 元素顺序保留:轮转后,元素的相对顺序需保持(如示例中 5、6、7 的相对顺序,1、2、3、4 的相对顺序均不变)。

二、核心解法:三次翻转法(原地高效)

三次翻转法的核心思想是 “通过翻转操作,将‘向右轮转’的复杂逻辑转化为三次简单的数组翻转”。其本质是利用翻转对元素顺序的改变,间接实现轮转效果,且全程无需开辟新数组,空间复杂度极低。

1. 为什么需要先对 k 取模?

由于数组轮转 n 步后会回到原始状态(例如 n=7,轮转 7 步后数组不变),因此当 k≥n 时,实际需要的轮转步数为 k_mod = k % n。这一步操作能减少不必要的计算(例如 k=10 时,只需处理 3 步而非 10 步),是优化解题的关键前提。

例如:

  • 当 n=7,k=3 时,k_mod=3,无需调整;
  • 当 n=7,k=10 时,k_mod=10%7=3,按 3 步处理;
  • 当 n=7,k=7 时,k_mod=0,无需轮转(数组不变)。

2. 三次翻转的逻辑原理

我们先明确 “向右轮转 k 步” 的效果:数组末尾的 k 个元素会移动到数组开头,其余元素向右顺延。例如,数组[a1,a2,a3,a4,a5,a6,a7](n=7),向右轮转 3 步后为[a5,a6,a7,a1,a2,a3,a4]—— 末尾 3 个元素[a5,a6,a7]到开头,前 4 个元素[a1,a2,a3,a4]顺延。

三次翻转法通过以下步骤实现这一效果:

  1. 翻转整个数组:将数组从 “前 n-k 个元素 + 后 k 个元素” 的结构,变为 “后 k 个元素的逆序 + 前 n-k 个元素的逆序”;
  1. 翻转前 k 个元素:将 “后 k 个元素的逆序” 恢复为原顺序,此时前 k 个元素就是轮转后需要放在开头的元素;
  1. 翻转后 n-k 个元素:将 “前 n-k 个元素的逆序” 恢复为原顺序,此时后 n-k 个元素就是轮转后需要放在末尾的元素。

简单来说,三次翻转的逻辑链是:整体翻转打乱顺序→局部翻转恢复目标区域顺序→最终得到轮转结果

3. 示例演示(以nums = [1,2,3,4,5,6,7],k=3为例)

步骤 1:计算 k_mod

n=7,k=3,k_mod=3%7=3。

步骤 2:第一次翻转(翻转整个数组)

原数组:[1,2,3,4,5,6,7]

翻转后:[7,6,5,4,3,2,1]

作用:将末尾的 3 个元素(5,6,7)翻转为(7,6,5),移到数组前半部分;将前 4 个元素(1,2,3,4)翻转为(4,3,2,1),移到数组后半部分。

步骤 3:第二次翻转(翻转前 k_mod=3 个元素)

当前数组:[7,6,5,4,3,2,1]

翻转前 3 个元素:[5,6,7,4,3,2,1]

作用:将前 3 个元素(7,6,5)恢复为原顺序(5,6,7),这正是轮转后需要放在开头的元素。

步骤 4:第三次翻转(翻转后 n-k_mod=4 个元素)

当前数组:[5,6,7,4,3,2,1]

翻转后 4 个元素:[5,6,7,1,2,3,4]

作用:将后 4 个元素(4,3,2,1)恢复为原顺序(1,2,3,4),这正是轮转后需要放在末尾的元素。

最终结果与题目预期完全一致,验证了三次翻转法的正确性。

4. 翻转操作的实现

翻转数组的某一段(从索引 left 到索引 right)是三次翻转法的基础操作,实现逻辑如下:

  • 初始化两个指针,left 指向段的起始索引,right 指向段的结束索引;
  • 交换 left 和 right 指向的元素,然后 left 向右移动 1 位,right 向左移动 1 位;
  • 重复上述操作,直到 left ≥ right(即指针相遇或交叉,段内元素全部交换完毕)。

例如,翻转数组[7,6,5](left=0,right=2):

  • 交换 7 和 5 → [5,6,7],left=1,right=1;
  • left ≥ right,翻转结束。

三、其他常见解法(对比参考)

除了三次翻转法,“轮转数组” 还有其他解法,虽然复杂度不如三次翻转法最优,但能帮助我们从不同角度理解问题,以下简要介绍两种:

1. 额外数组法(空间复杂度 O (n))

思路

开辟一个与原数组长度相同的新数组,将原数组中 “需要轮转的元素” 按目标顺序放入新数组,最后将新数组的值复制回原数组。

  • 对于原数组索引 i 的元素,轮转后在新数组的索引为 (i + k) % n(向右轮转 k 步);
  • 也可直接定位:新数组前 k 个元素对应原数组末尾 k 个元素(索引 n-k 到 n-1),新数组后 n-k 个元素对应原数组前 n-k 个元素(索引 0 到 n-k-1)。
优缺点
  • 优点:逻辑直观,易于理解和实现,无需复杂的翻转操作;
  • 缺点:需要开辟额外数组,空间复杂度为 O (n),不如三次翻转法高效。

2. 多次右移法(时间复杂度 O (nk))

思路

每次只将数组向右轮转 1 步,重复 k 次。轮转 1 步的逻辑是:保存数组最后一个元素,然后将其余元素从后向前依次右移 1 位,最后将保存的元素放到数组开头。

优缺点
  • 优点:逻辑简单,无需复杂算法,仅需基础的元素移动操作;
  • 缺点:时间复杂度为 O (nk)(每次轮转 1 步需 O (n) 时间,共 k 次),当 k 较大时(如 k=n),时间复杂度会达到 O (n²),效率极低。

四、复杂度分析(三次翻转法)

1. 时间复杂度:O (n)

  • 翻转操作的时间复杂度:翻转一段长度为 L 的数组,需要交换 L//2 次元素,时间复杂度为 O (L);
  • 三次翻转的总时间:第一次翻转整个数组(O (n)),第二次翻转前 k 个元素(O (k)),第三次翻转后 n-k 个元素(O (n-k)),总时间为 O (n) + O (k) + O (n-k) = O (n);
  • 整体时间:加上 k 取模的 O (1) 操作,总时间复杂度为 O (n)。

2. 空间复杂度:O (1)

  • 整个过程仅用到了几个额外变量(如 left、right 指针,k_mod 等),没有开辟新的数组或其他数据结构;
  • 所有翻转操作都在原数组上完成,额外空间的使用与数组长度 n 无关,因此空间复杂度为常数级的 O (1)。

五、三次翻转法代码实现

以下以 Python,Java 为例,实现三次翻转法,核心是先实现 “段翻转” 函数,再执行三次翻转:

1,Python

class Solution:def rotate(self, nums: List[int], k: int) -> None:def reversed(i: int, j: int):while i < j:nums[i], nums[j] = nums[j], nums[i]i, j = i + 1, j - 1n = len(nums)k %= nreversed(0, n - 1)reversed(0, k - 1)reversed(k, n - 1)

2,Java

class Solution {int[] nums;public void rotate(int[] nums, int k) {this.nums = nums;int n = nums.length;k %= n;reversed(0, n - 1);reversed(0, k - 1);reversed(k, n - 1);}private void reversed(int i, int j) {for (; i < j; i++, j--) {int t = nums[i];nums[i] = nums[j];nums[j] = t;}}
}

你可以将上述代码复制到 LeetCode 编辑器中测试,完全符合题目要求。

六、总结与拓展

三次翻转法是解决 “轮转数组” 问题的最优解,其核心优势在于 “线性时间 + 常数空间”,且逻辑可迁移到类似的 “元素循环移动” 问题中。需要注意的是,三次翻转法的逻辑不仅适用于 “向右轮转”,也可调整为 “向左轮转”:

拓展:向左轮转 k 步的三次翻转法

若题目要求 “向左轮转 k 步”(例如[1,2,3,4,5,6,7]向左轮转 3 步,结果为[4,5,6,7,1,2,3]),只需调整三次翻转的顺序:

  1. 计算 k_mod = k % n;
  1. 第一次翻转:翻转前 k_mod 个元素;
  1. 第二次翻转:翻转后 n-k_mod 个元素;
  1. 第三次翻转:翻转整个数组。

例如,[1,2,3,4,5,6,7]向左轮转 3 步:

  • 翻转前 3 个元素:[3,2,1,4,5,6,7];
  • 翻转后 4 个元素:[3,2,1,7,6,5,4];
  • 翻转整个数组:[4,5,6,7,1,2,3],与预期结果一致。

掌握三次翻转法的核心逻辑,能帮你轻松应对 “数组轮转” 的各种变体问题,体现算法思维的灵活性。

希望通过本文的讲解,你能不仅学会 “轮转数组” 的解法,更能深入理解三次翻转法的原理,将其灵活应用到类似的 “元素顺序调整” 问题中,提升面试竞争力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98708.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98708.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络编程---TCP

1.TCP&#xff1a;传输控制协议&#xff0c;位于传输层2.TCP的特性&#xff1a;a.使用流式套接字&#xff0c;数据连续&#xff0c;有顺序b.TCP是可靠传输&#xff0c;有有应答机制ACK&#xff0c;即收到数据后会明确告知发送方已收到数据&#xff1b;若发送方没有在预计时间收…

对计算机网络模型的理解

文章目录 目录 前言 一、Internet 的核心特点 二、Internet 的组成结构 1. 硬件基础&#xff1a;网络运行的 “物理载体” 2. 软件支撑&#xff1a;网络运行的 “功能桥梁” 3. 协议规则&#xff1a;网络运行的 “通用语言” 三、OSI 七层参考模型&#xff08;理论标准&…

每日一算:分发糖果

在算法面试中&#xff0c;“分发糖果” 是一道经典的贪心算法应用题&#xff0c;核心考察对 “局部最优推导全局最优” 的理解。本文将从问题分析出发&#xff0c;提供两种主流解题思路&#xff0c;并附上 C 实现代码&#xff0c;帮助你彻底掌握这道题。一、问题重述题目要求有…

【WorkManager】无法在 Direct Boot 模式下初始化

【WorkManager】无法在 Direct Boot 模式下初始化一、问题描述二、问题分析2.1 关于 Direct Boot 模式2.2 支持 Direct Boot 模式2.3 手动初始化 WorkManager 组件2.4 WorkManager 不支持 Direct Boot 的官方修改三、解决方案一、问题描述 在使用 WorkManager 库来实现开机上报…

Hybrid应用性能优化实战分享(本文iOS 与 H5为例,安卓同理)

前言在移动应用开发中&#xff0c;Hybrid 架构因其跨平台特性和开发效率优势被广泛采用。然而&#xff0c;WebView 的性能问题一直是开发者面临的挑战。本文将基于实际项目经验&#xff0c;分享 iOS Hybrid 应用的核心优化策略&#xff0c;涵盖 WebView 池化、预加载、用户体验…

点积、叉积、矩阵行列式详解、线性相关与线性无关、矩阵的秩、矩阵可逆与不可逆详解

1.向量 1.1 点积&#xff08;Dot Product&#xff09; 1.1.1 定义 点积是在求一个标量&#xff0c;点积结果没有方向。 对于两个向量u(u1,u2,u3),v(v1,v2,v3)\bold{u}(u_1,u_2,u_3),\bold{v}(v_1,v_2,v_3)u(u1​,u2​,u3​),v(v1​,v2​,v3​) 点积定义为&#xff1a;u⋅vu1v1u…

Mac安装nvm详细教程(超简单)

本章教程,主要介绍如何在Mac操作系统上安装nvm. 我们使用官方一键安装脚本,完成安装 一、安装步骤 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash配置环境变量,编辑.zshrc文件 vim .zshrcexport NVM_DIR="$(

【selenium】网页元素找不到?从$(‘[placeholder=“手机号“]‘)说起

网页元素找不到&#xff1f;从$(‘[placeholder“手机号”]’)说起总结&#xff1a;控制台不骗人&#xff0c;元素选不到&#xff0c;八成是写法、时机或环境的问题。我们在写网页自动化脚本或者调试页面的时候&#xff0c;经常遇到一个让人头疼的问题&#xff1a;明明元素就在…

SSE 模仿 GPT 响应

后端代码 const express require(express) const cors require(cors);const app express(); app.use(cors()); const port 3000;app.listen(port, () > {console.log(Server running at http://localhost:${port}/); });const msg 全国同胞们&#xff0c; 尊敬的各位国…

MAC 多个版本 JDK进行切换

1.查看本机所有的jdk/usr/libexec/java_home -V2、打开bash_profile文件。可以在终端vim ~/.bash_profile打开&#xff0c;也可以打开访达shiftcmdG然后输入/Users/mac/.bash_profile&#xff08;本机bash_profile的路径&#xff09;加入新的环境变量格式如下&#xff08;参考我…

shell 中 expect 详解

一、概述Expect是一个免费的编程工具语言&#xff0c;用来实现自动和交互式任务进行通信&#xff0c;而无需人的干预。Expect的作者DonLibes在1990年开始编写Expect时对Expect做有如下定义&#xff1a;Expect是一个用来实现自动交互功能的软件套件。通过expect系统管理员可以创…

第4讲 机器学习基础概念

机器学习作为人工智能的子领域&#xff0c;专注于训练计算机算法自动发现数据中的模式与关联关系。以下是其核心基础概念&#xff1a;4.1 数据数据是机器学习的基石。缺乏数据&#xff0c;算法将无从学习。数据可呈现为结构化数据&#xff08;如电子表格、数据库&#xff09;和…

Go组合式继承:灵活替代方案

Go 语言没有传统面向对象编程中的继承机制&#xff0c;但通过组合和接口实现类似功能。Go 更提倡组合优于继承的设计原则&#xff0c;这种设计方式更灵活且易于维护。结构体组合&#xff08;伪继承&#xff09;通过嵌套结构体实现类似继承的效果。子结构体可以直接访问父结构体…

Verilog三段式FSM,实现十字路口红绿灯

运行环境&#xff1a;VCS verdi状态说明&#xff1a;S0 &#xff1a; 初始状态 S1 &#xff1a; 东西方向绿灯亮&#xff0c;南北方向红灯亮&#xff1b;点亮30周期 S2 &#xff1a; 东西方向黄灯亮&#xff0c;南北方向红灯亮&#xff1b;点亮2 周期 S3 &#xff1a; 东西方向…

java 将pdf转图片

如何将pdf文件转为图片 import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.PDFRenderer; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class Pdf2Png {/**…

手搓Spring

目录 两种方法创建Spring容器 自定义Spring容器及前置操作 Spring扫描逻辑实现 createBean()方法 getBean()方法 依赖注入&#xff08;DI&#xff09; BeanNameAware接口 InitializingBean接口 BeanPostProcessor接口 AOP的实现 Spring 是一个轻量级的 Java 开发框架…

.NET 单文件程序详解:从原理到实践

C# 混淆加密大师在最新版本中, 提供了.NET单文件解包打包功能, 它可以快速解包官方打包的单文件程序&#xff0c;恢复为原始的多文件结构。也可以对解包后的程序集进行混淆与加密&#xff0c;有效提升逆向门槛。最后还能重新打包成单文件程序&#xff0c;保持对用户友好的分发形…

Spring面试题记录?

请简述 Spring 框架的核心是什么&#xff1f;它主要包含了哪些核心模块&#xff1f; spring的核心模块主要有spring-core&#xff08;工具类&#xff0c;资源加载&#xff09;&#xff0c;spring-bean&#xff08;bean的定义&#xff0c;创建&#xff0c;封装&#xff09;&…

一次缓存引发的文件系统数据不一致问题排查与深度解析

01 起因EFC&#xff08;Elastic File Client&#xff09;是 NAS 自研的分布式文件系统客户端&#xff0c;最近完成了对缓存架构的更新&#xff0c;现在支持多个客户端之间构成分布式缓存&#xff0c;底层支持 NAS、CPFS 和 OSS。由于开发时间较短&#xff0c;一直没有做 NAS 场…

Spring Boot Gateway 教程:从入门到精通

一、Spring Cloud Gateway 简介Spring Cloud Gateway 是基于 Spring 5、Project Reactor 和 Spring Boot 2 构建的 API 网关&#xff0c;旨在为微服务架构提供一种简单而有效的路由管理方式。它取代了 Netflix Zuul&#xff0c;提供了更高效和更强大的网关解决方案。核心特点&a…