Leetcode 189: 轮转数组

news2025/3/4 18:53:38

Leetcode 189: 轮转数组

这是一道经典问题,题目要求将一个数组向右轮转 k 个位置,有多种解法可以快速求解,既可以通过额外空间,也可以在 O(1) 的空间复杂度内完成。本题考察数组操作、双指针,以及算法优化能力。


题目描述

输入:

  • 一个整数数组 nums
  • 一个整数 k(表示右移的次数)。

输出:

  • 将数组元素旋转 k 次后直接修改原数组,不返回值。

示例输入输出:

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

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

解法 1:额外数组辅助

思路
  1. 使用一个额外的数组 temp 来保存最终的旋转结果。
  2. 拷贝操作
    • 遍历原数组,将 nums[i] 放置到新位置 (i + k) % n 中。
  3. 覆盖结果
    • temp 中的内容转存回原数组。

代码模板
class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k %= n; // 如果 k 大于数组长度,需要取模

        int[] temp = new int[n];
        for (int i = 0; i < n; i++) {
            temp[(i + k) % n] = nums[i]; // 按照旋转后的位置存储
        }

        // 将 temp 的内容拷贝到原数组
        for (int i = 0; i < n; i++) {
            nums[i] = temp[i];
        }
    }
}

复杂度分析
  • 时间复杂度:O(n)
    • 遍历数组两次,一次构造 temp 数组,一次拷贝回原数组。
  • 空间复杂度:O(n)
    • 需要一个额外大小为 n 的数组存放临时结果。

解法 2:环状替换

思路
  1. 核心观察
    • 通过旋转,数组中的每个元素其实沿着环状路径被移动,例如第 i 个元素移动到位置 (i + k) % n
    • 从某个点出发,将该点开始的所有元素按照这种环状方式重新排列。
    • 当访问过的元素数量达到数组大小 n 时,正好完成所有元素的轮转。
  2. 实现步骤
    • 统计当前访问过的元素数量 count,从未访问过的某个起始点出发进行 “环绕替换”。
    • 对于每个元素,将其移至新位置 (i + k) % n,直到形成一个环,然后跳到下一个未访问的点。

代码模板
class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k %= n; // 如果 k 大于数组长度,取模去掉多余轮转

        int count = 0; // 记录访问的元素数量
        for (int start = 0; count < n; start++) { // 从未访问的点开始
            int current = start; // 当前节点
            int prev = nums[start]; // 保存当前值

            do {
                int next = (current + k) % n; // 下一个位置
                int temp = nums[next]; // 保存下个位置的值
                nums[next] = prev; // 替换值
                prev = temp; // 更新 "前一个值"
                current = next; // 跳到下一个位置
                count++; // 更新访问数量
            } while (current != start); // 环绕回起点时退出
        }
    }
}

复杂度分析
  • 时间复杂度:O(n)
    • 每个元素最多被访问一次。
  • 空间复杂度:O(1)
    • 没有使用额外数据结构,原地旋转。

解法 3:数组翻转技巧

思路
  1. 数组轮转可以通过 三步翻转 实现:
    • 第 1 步:翻转整个数组;
    • 第 2 步:翻转前 k 个元素;
    • 第 3 步:翻转后 n-k 个元素。
  2. 实现原理:
    • 经过数组翻转操作后,元素将被正确排列。
    • 例如:对于输入 nums = [1,2,3,4,5,6,7], k=3
      原始: [1, 2, 3, 4, 5, 6, 7]
      步骤 1 翻转整个数组: [7, 6, 5, 4, 3, 2, 1]
      步骤 2 翻转前 k 个元素:[5, 6, 7, 4, 3, 2, 1]
      步骤 3 翻转后 n-k 个元素:[5, 6, 7, 1, 2, 3, 4]
      

代码模板
class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        k %= n; // 如果 k 大于数组长度,取模处理

        // 翻转函数
        reverse(nums, 0, n - 1); // 翻转整个数组
        reverse(nums, 0, k - 1); // 翻转前 k 个元素
        reverse(nums, k, n - 1); // 翻转后 n-k 个元素
    }
    
    private void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

复杂度分析
  • 时间复杂度:O(n)
    • 翻转整个数组花费 O(n),翻转前后两部分各花费 O(k) 和 O(n-k),总时间为 O(n)。
  • 空间复杂度:O(1)
    • 翻转操作原地完成,没有额外数据结构。

解法 4:双指针 + 循环节

思路
  • 使用双指针从两端到中间进行元素筛选调整。
  • 或者结合环状数组的位置动态安排记录。


总结:如何快速 AC?

  1. 优先选择三步翻转解法:O(n) 时间复杂度,O(1) 空间复杂度,实现简单,效率最高,是面试中优先推荐的解法。
  2. 针对特殊场景
    • 如果原数组不可修改,可以选择额外数组解法。
    • 如果需要一定技巧性(如比特运算分析竞赛题),环状替换法更具逻辑挑战。
  3. 边界情况注意
    • k 大于数组长度时,需要取模:k %= n
    • 空数组或 k=0 时,直接返回。

通过掌握以上 3 种高效解法(特别是三步翻转技巧),不仅可以轻松解决问题,还能给面试官留下深刻印象。

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

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

相关文章

使用vue3+element plus 的table自制的穿梭框(支持多列数据)

目录 一、效果图 二、介绍 三、代码区 一、效果图 话不多说&#xff0c;先上图 二、介绍 项目需要&#xff1a;通过穿梭框选择人员信息&#xff0c;可以根据部门、岗位进行筛选&#xff0c;需要显示多列&#xff08;不光显示姓名&#xff0c;还包括人员的一些基础信息&…

Java【多线程】(2)线程属性与线程安全

目录 1.前言 2.正文 2.1线程的进阶实现 2.2线程的核心属性 2.3线程安全 2.3.1线程安全问题的原因 2.3.2加锁和互斥 2.3.3可重入&#xff08;如何自己实现可重入锁&#xff09; 2.4.4死锁&#xff08;三种情况&#xff09; 2.4.4.1第一种情况 2.4.4.2第二种情况 2.4…

vue These dependencies were not found

These dependencies were not found: * vxe-table in ./src/main.js * vxe-table/lib/style.css in ./src/main.js To install them, you can run: npm install --save vxe-table vxe-table/lib/style.css 解决&#xff1a; nodejs执行以下语句 npm install --save vxe-t…

Yak 在 AI 浪潮中应该如何存活?

MCP 是 Claude 发起的一个协议&#xff0c;在2024年10月左右发布&#xff0c;在2025年2月开始逐步有大批量的 AI 应用体开始支持这个协议。这个协议目的是让 AI 同时可以感知有什么工具可以用&#xff0c;如果要调用这些工具的话&#xff0c;应该是用什么样的方式。 这个 MCP 协…

AI是否能真正理解人类情感?从语音助手到情感机器人

引言&#xff1a;AI与情感的交集 在过去的几十年里&#xff0c;人工智能&#xff08;AI&#xff09;的发展速度令人惊叹&#xff0c;从简单的语音识别到如今的深度学习和情感计算&#xff0c;AI已经深入到我们生活的方方面面。尤其是在语音助手和情感机器人领域&#xff0c;AI不…

大语言模型学习--本地部署DeepSeek

本地部署一个DeepSeek大语言模型 研究学习一下。 本地快速部署大模型的一个工具 先根据操作系统版本下载Ollama客户端 1.Ollama安装 ollama是一个开源的大型语言模型&#xff08;LLM&#xff09;本地化部署与管理工具&#xff0c;旨在简化在本地计算机上运行和管理大语言模型…

linux上面安装 向量数据库 mlivus和 可视化面板Attu

1. 确保docker(docker 19.0以上即可) 和 docker-compose&#xff08;V2.2.2以上&#xff09; 都已安装 2. 创建milvus工作目录 # 新建一个名为milvus的目录用于存放数据 目录名称可以自定义 mkdir milvus# 进入到新建的目录 cd milvus 3. 下载并编辑docker-compose.yml 在下载…

用工厂函数简化redis配置

工厂函数&#xff08;Factory Function&#xff09;不同于构造函数&#xff0c;工厂函数就是一个普通函数&#xff0c;通常用于创建对象或实例。它的核心思想是通过一个函数来封装对象的创建逻辑&#xff0c;而不是直接使用类的构造函数。工厂函数可以根据输入参数动态地决定创…

类和对象-继承-C++

1.定义 面向对象的三大特征之一&#xff0c;为了减少重复的代码 2.语法 class 子类 &#xff1a;继承方式 父类 &#xff08;子类也叫派生类&#xff0c;父类也称为基类&#xff09; 例&#xff1a;class age&#xff1a;public person&#xff1b; #include<iostrea…

使用Maven搭建Spring Boot框架

文章目录 前言1.环境准备2.创建SpringBoot项目3.配置Maven3.1 pom.xml文件3.2 添加其他依赖 4. 编写代码4.1 启动类4.2 控制器4.3 配置文件 5.运行项目6.打包与部署6.1 打包6.2 运行JAR文件 7.总结 前言 Spring Boot 是一个用于快速构建 Spring 应用程序的框架&#xff0c;它简…

RockyLinux 为 k8s 集群做准备

1.准备VM 镜像 开启虚拟机 选择安装 Rocky linux 9.5 软件选择最小安装就可以了 在 rocky 9 以后版本中 他全部 采用 network manager 去替换老的 network 去实现网络的管理 1.网卡配置 cat /etc/NetworkManager/system-connections/ens160.nmconnection 我们配置了两块网…

二十三种设计模式

2 工厂方法模式 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通…

SqlSugar 语法糖推荐方式

//方式1&#xff1a;var dd _repository._Db.Queryable<ConfigAggregateRoot, UserRoleEntity>((o, p) > o.Id p.Id).Select((o, p) > new{o.Id,o.Remark,p.RoleId,});//方式2&#xff1a;不推荐使用&#xff0c;建议优先使用 Lambda 表达式&#xff0c;因为它更…

SQL 全面指南:从基础语法到高级查询与权限控制

SQL&#xff1a;全称 Structured Query Language&#xff0c;结构化查询语言。操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准 。 一、SQL通用语法 在学习具体的SQL语句之前&#xff0c;先来了解一下SQL语言的同于语法。 1). SQL语句可以单行或多…

Spring Cloud Gateway 网关的使用

在之前的学习中&#xff0c;所有的微服务接口都是对外开放的&#xff0c;这就意味着用户可以直接访问&#xff0c;为了保证对外服务的安全性&#xff0c;服务端实现的微服务接口都带有一定的权限校验机制&#xff0c;但是由于使用了微服务&#xff0c;就需要每一个服务都进行一…

JavaWeb-jdk17安装

下载jdk17 地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#jdk17-windows 安装jdk 配置环境变量 右键点击我的电脑>属性>高级系统设置>环境变量 在系统变量Path变量中添加 测试 java -version javac -version

【银河麒麟高级服务器操作系统】服务器测试业务耗时问题分析及处理全流程分享

更多银河麒麟操作系统产品及技术讨论&#xff0c;欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer…

算法1-4 蜜蜂路线

题目描述 一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你&#xff1a;蜜蜂从蜂房 m 开始爬到蜂房 n&#xff0c;m<n&#xff0c;有多少种爬行路线&#xff1f;&#xff08;备注&#xff1a;题面有误&#xff0c;右上角应为 n−…

Android 常见View的防抖

在开发Android应用时&#xff0c;我们经常会遇到用户快速点击按钮或者频繁触发某个事件的情况。这种行为可能会导致不必要的重复操作&#xff0c;例如多次提交表单、重复加载数据等。为了避免这些问题&#xff0c;我们需要对这些事件进行防抖处理。本文将详细介绍如何在Kotlin中…

数据库原理SQL查询(习题+知识点)

一、查询学生表所有学生记录 1.题目内容代码编写 select * from stu; 2.知识点提醒 1&#xff09;选择表中的所有属性列有两种方法 在select关键字后列出所有列名若列的显示顺序与其在表中的顺序相同&#xff0c;则也可用 * 表示所有列 二、查询学生表中部分信息 1.题目内…