从风扇叶片到数组轮转:探索轮转数组问题

生活中的算法

想象你在看一个风扇缓缓转动,每次转动三个叶片的距离。原本在上方的叶片转到了右侧,原本在右侧的叶片转到了下方...这就是一个生动的轮转过程。再比如,幼儿园老师让小朋友们围成一个圈,喊"向右移动3个位置",每个小朋友就会走到新的位置上。

这种轮转在生活中处处可见:餐厅的轮转座位安排、值班表的轮转、超市商品的轮换陈列,甚至是农田的轮作制度。它们都体现了同样的规律:保持原有顺序,整体移动特定步数。

问题描述

LeetCode第189题"轮转数组"是这样描述的:给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

例如:

输入: 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]

最直观的解法:临时数组

就像小朋友们轮转位置时,先站到新位置再坐下。我们可以用一个临时数组记录每个元素的新位置。

让我们用一个简单的例子来理解:

原数组:[1,2,3,4], k = 2
1. 创建临时数组:[0,0,0,0]
2. 1应该移动到位置(0+2)%4=2:[0,0,1,0]
3. 2应该移动到位置(1+2)%4=3:[0,0,1,2]
4. 3应该移动到位置(2+2)%4=0:[3,0,1,2]
5. 4应该移动到位置(3+2)%4=1:[3,4,1,2]
6. 复制回原数组:[3,4,1,2]

优化解法:三次翻转

仔细观察会发现一个有趣的规律:如果我们把数组分成两部分,右边k个元素和左边其余元素,只需要三步就能完成轮转:

  1. 翻转整个数组
  2. 翻转前k个元素
  3. 翻转后面的元素

就像打扑克牌时的切牌技巧:先整叠反转,再分别调整两叠的顺序。

三次翻转的原理

用餐桌座位来理解:

  1. 所有人起立,从左到右交换位置(整体翻转)
  2. 前k个人调整自己的相对位置(前k个翻转)
  3. 剩下的人调整自己的相对位置(剩余部分翻转)

示例演示

用nums = [1,2,3,4,5], k = 2来说明:

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

1. 整体翻转:
[1,2,3,4,5] -> [5,4,3,2,1] 2. 翻转前k个:
[5,4,3,2,1] -> [4,5,3,2,1] 3. 翻转剩余部分:
[4,5,3,2,1] -> [4,5,1,2,3]

Java代码实现

public void rotate(int[] nums, int k) {
if (nums == null || nums.length <= 1) {
return;
} // 处理k大于数组长度的情况
k = k % nums.length;
if (k == 0) return; // 1. 翻转整个数组
reverse(nums, 0, nums.length - 1); // 2. 翻转前k个元素
reverse(nums, 0, k - 1); // 3. 翻转剩余元素
reverse(nums, k, nums.length - 1);
} 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(n)
  • 空间复杂度:O(1)
  • 优点:空间效率高,实现简单
  • 缺点:思路不够直观

思考启发

这道题告诉我们:

  1. 有时候直观的解法不一定是最优的
  2. 观察数据规律很重要
  3. 在处理环形结构时,取余运算很有用
  4. 翻转操作可以用来改变元素位置关系

类似的问题还有:

  • 反转字符串
  • 字符串轮转
  • 循环队列的实现

小结

通过轮转数组这道题,我们不仅学会了一个经典的数组操作技巧,更重要的是理解了如何通过观察数据特征,找到优雅的解决方案。记住,当遇到需要移动元素位置的问题时,考虑一下翻转操作是否能帮助我们!


作者:忍者算法

公众号:忍者算法

我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~

【忍者算法】从风扇叶片到数组轮转:探索轮转数组问题|LeetCode 189 轮转数组的更多相关文章

  1. 前端与算法 leetcode 189. 旋转数组

    目录 # 前端与算法 leetcode 189. 旋转数组 题目描述 概要 提示 解析 算法 # 前端与算法 leetcode 189. 旋转数组 题目描述 189. 旋转数组 概要 把他当做一到简单 ...

  2. LeetCode 189. 旋转数组(Rotate Array)

    189. 旋转数组 LeetCode189. Rotate Array 题目描述 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: [1,2,3,4,5,6, ...

  3. Java实现 LeetCode 189 旋转数组

    189. 旋转数组 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: [1,2,3,4,5,6,7] 和 k = 3 输出: [5,6,7,1,2,3,4] ...

  4. Leetcode 189.旋转数组 By Python

    给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: [1,2,3,4,5,6,7] 和 k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右旋转 1 ...

  5. leetcode 189. 旋转数组(python)

    给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: [1,2,3,4,5,6,7] 和 k = 3输出: [5,6,7,1,2,3,4]解释:向右旋转 1 步: ...

  6. leetcode 189 旋转数组

    class Solution(object): def rotate(self, nums, k): """ :type nums: List[int] :type k: ...

  7. [数组] Leetcode 189.旋转数组

  8. c++ LeetCode(初级数组篇)十一道算法例题代码详解(一)

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/10940636.html 唉!最近忙着面试找实习,然后都是面试的很多是leetcode的算法题, ...

  9. php 把一个数组分成有n个元素的二维数组的算法

    一.第一种解法 <?php //把一个数组分成几个数组 //$arr 是数组 //$num 是数组的个数 function partition($arr,$num){ //数组的个数 $list ...

  10. LeetCode:删除排序数组中的重复项||【80】

    LeetCode:删除排序数组中的重复项||[80] 题目描述 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原 ...

随机推荐

  1. 如何把composer版本降下来

    如果想把composer从2版本降到1版本 composer self-update 1.4.1 如果想降到1版本 composer self-update --1

  2. 洛谷P4913【深基16.例3】二叉树深度题解优化Pro Max版

    原题指路 原题解指路 前情提要:不懂什么是 DFS 的小伙伴可以看看一下这段文字(摘自OIwiki): DFS 最显著的特征在于其 递归调用自身.同时与 BFS 类似,DFS 会对其访问过的点打上访问 ...

  3. ETCD存储满了如何处理?

    一.前言 当运行 ETCD 日志报 Erro: mvcc database space exceeded 时,或者查看健康状态显示 failed to commit proposal: Active ...

  4. golang之泛型

    Go 1.18版本增加了对泛型的支持,泛型也是自 Go 语言开源以来所做的最大改变. 泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型.ーー换句话 ...

  5. 【C++】static 知识整理 【静态与局部静态】

    目录 类外 类内 局部静态 local static 类外 类内 类外 C++的静态可以分为两种情况来讨论:在类外和在类内. 对于静态变量/函数,链接将只在内部 (如果不用static,那么在不同文件 ...

  6. android emulator 设置代理

    android emulator 设置代理 由于开发的 app 需要访问 google 服务,那么跑虚拟机的时候就需要设置网络代理,试了几种方法都没成功,记录一下 因为已知我开发电脑的代理地址和端口, ...

  7. Flutter自动生成安卓和IOS图标

    flutter_launcher_icons 用这个库自动生成 首先添加依赖 dev_dependencies: flutter_launcher_icons: flutter_icons: andr ...

  8. docker 1.13版本修改默认存储路径及添加私有registry

    1.服务器安装dockeryum install docker -y12.修改配置文件方法1: 编辑 `/etc/sysconfig/docker`文件 修改`OPTION`选项 添加 --insec ...

  9. Win10正式专业版激活方法

      首先,我们先查看一下Win10正式专业版系统的激活状态: 点击桌面左下角的"Windows"按钮,从打开的扩展面板中依次点击"设置"-"更新和安全 ...

  10. VS2008新建MFC程序时提示:当前页面的脚本发送错误 不是有效的Win32应用程序的解决办法

    错误现象: 解决方案: 1.根据错误信息中的url,找到对应文件夹下的htm文件 2.使用notepad++打开default.htm文件,找到错误提示地方,注释掉其中两句语句,如433和434行所示 ...