189. 旋转数组

难度简单

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例 1:

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

示例 2:

输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]

说明:

分析

方法 1:暴力

最简单的方法是旋转 k 次,每次将数组旋转 1 个元素。

  • Java
public class Solution {public void rotate(int[] nums, int k) {int temp, previous;for (int i = 0; i < k; i++) {previous = nums[nums.length - 1];for (int j = 0; j < nums.length; j++) {temp = nums[j];nums[j] = previous;previous = temp;}}}
}

复杂度分析

  • 时间复杂度:O(n*k) 。每个元素都被移动 1 步(O(n)) k次(O(k)) 。
  • 空间复杂度:O(1) 。没有额外空间被使用。

方法 2:使用额外的数组

算法

我们可以用一个额外的数组来将每个元素放到正确的位置上,也就是原本数组里下标为 ii 的我们把它放到 (i+k)%数组长度的位置。然后把新的数组拷贝到原数组中。

  • Java
public class Solution {public void rotate(int[] nums, int k) {int[] a = new int[nums.length];for (int i = 0; i < nums.length; i++) {a[(i + k) % nums.length] = nums[i];}for (int i = 0; i < nums.length; i++) {nums[i] = a[i];}}
}

复杂度分析

  • 时间复杂度: O(n) 。将数字放到新的数组中需要一遍遍历,另一边来把新数组的元素拷贝回原数组。
  • 空间复杂度: O(n)。另一个数组需要原数组长度的空间。

方法 3:使用环状替换

算法

我们假设现在有 A 、B 、C、 D、 E五名同学,今天考试完,老师要求换座位,每个同学向后移动3个座位
于是就从 A 同学开始换座位了… (下图左边

  1. A同学 非常自觉,看了看自己座位号(0),根据老师要求,他走到了3 号位置,即 D 同学的位置,同时他把D 同学赶到了角落,自己坐在了 3 号位置,第一个完成任务真爽!
  2. D同学 一看,不行啊,我咋能呆在角落,于是D同学也按要求理直气壮来到了1号位置,同样把B同学赶到了角落,猛男落泪…
  3. B同学 当然也不干,气汹汹走到了4号位置,“E同学,麻烦起来一下,角落给你收拾好了:)”,于是 E同学来到角落…
  4. E同学 一想:不行呀,我这么帅,必须有座位!站起来跑到了2号位置,二话不说,赶走了C,坐上上去,一下子舒服了…
  5. C同学 此时来了角落,想:不是每个人都有座位吗??还需要抢?于是C从容的来到了0号位置,至此,所有同学都坐好了。

以上是 下图中左边 的情况,这个算法还会遇到另外一种情况,就是今天E同学请假,老师说那就每个人往后移动 2个座位。于是大家开始行动,和上面发生的一样,不过,当第二轮C同学坐好了以后,角落没人了,大家都有位子,就没人闹意见了…
老师一看,我精心布置的局,咋就停了呢,于是吼了一嗓子:“咳咳!还有谁没换?第二组打头的那个!B同学!是不是你!你们第二组学学第一组,第一组早早的换完了,你们组还一个没动!”
B同学一听到喊自己的名字,秒怂…本来想偷懒,无奈换起来座位…就这样,随着第二组的同学换完座位,最终大家完成了换座位
(上面老师喊的那一嗓子,就是我们内循环退出,即C回到了起始位置0位置,这时候我们就将起始位置 Start + 1)

(补充)关于上述两种情况何时出现:

其实是这样的,对于一个长度为 n 的数组,整体移动 k 个位置

  • 当 n 和 k 的最大公约数 等于 1 的时候:1 次遍历就可以完成交换;比如 n = 5, k = 3
  • 当 n 和 k 的最大公约数 不等于 1 的时候:1 次遍历是无法完成的所有元素归位,需要 m (最大公约数) 次

所以在最大公约数不为 1 的时候
比如 [A,B,C,D,E,F] 此时 n = 6 , k = 4 ,其最大公约数为 2 ,因此需要 2 轮循环
我们就可以把这个数组分成两部分来看:
第 1 轮循环(分组1): A E C [A]
第 2 轮循环(分组2): B F D [B]

  • :每一轮循环只会在自己的那一组上不停的遍历。所以
    数组的前 m 个元素,其实就是每一个分组的第一个元素,我们控制流程在每次发现一轮循环走到原点时+1

  • 那么如何判断所有的分组都执行归位了呢? 可以有两种方法来控制

    第一种:我们就用最大公约数 m 来控制外循环,代表总共有 m 轮循环
    第二种:由于n个元素归位需要n次交换,所以我们定义一个count代表交换次数,当 count = n 时完成

  • Java

class Solution {public void rotate(int[] nums, int k) {int len  = nums.length;k = k % len;int count = 0;         // 记录交换位置的次数,n个同学一共需要换n次for(int start = 0; count < len; start++) {int cur = start;       // 从0位置开始换位子int pre = nums[cur];   do{int next = (cur + k) % len;int temp = nums[next];    // 来到角落...nums[next] = pre;pre = temp;cur = next;count++;}while(start != cur)  ;     // 循环暂停,回到起始位置,角落无人}   }
}

复杂度分析

  • 时间复杂度:O(n) 。只遍历了每个元素一次。
  • 空间复杂度:O(1)。使用了常数个额外空间。

方法 4:使用反转

算法

这个方法基于这个事实:当我们旋转数组 k 次, k%n个尾部元素会被移动到头部,剩下的元素会被向后移动。

在这个方法中,我们首先将所有元素反转。然后反转前 k 个元素,再反转后面 n-k 个元素,就能得到想要的结果。

假设 n=7 且 k=3。

原始数组                  : 1 2 3 4 5 6 7
反转所有数字后             : 7 6 5 4 3 2 1
反转前 k 个数字后          : 5 6 7 4 3 2 1
反转后 n-k 个数字后        : 5 6 7 1 2 3 4 --> 结果
  • Java
public class Solution {public void rotate(int[] nums, int k) {k %= nums.length;reverse(nums, 0, nums.length - 1);reverse(nums, 0, k - 1);reverse(nums, k, nums.length - 1);}public 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) 。 n 个元素被反转了总共 3 次。
  • 空间复杂度:O(1) 。 没有使用额外的空间。

【leetcode】189.旋转数组 (四种方法开阔思路,java实现!)相关推荐

  1. Leetcode 189. 旋转数组 解题思路及C++实现

    方法一:暴力方法 解题思路: 用栈存储后面的 k 个元素,然后将 nums 数组的元素往后挪 k 位,然后再将栈中的元素存进nums数组中. class Solution { public:void ...

  2. Leetcode 189. 旋转数组 (每日一题 20210909)

    给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数.进阶:尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题. 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问 ...

  3. leetcode(189) 旋转数组

    **给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 进阶: 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题. 你可以使用空间复杂度为 O(1) 的 原地 算法解 ...

  4. LeetCode 189. 旋转数组(环形替换)

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

  5. 【leetcode】412.Fizz Buzz (三种方法开阔思路,java实现)

    412. Fizz Buzz 难度简单 写一个程序,输出从 1 到 n 数字的字符串表示. 如果 n 是3的倍数,输出"Fizz": 如果 n 是5的倍数,输出"Buzz ...

  6. leetcode 189. 旋转数组

    题目 思路 先左边翻转,再右边翻转,最后整体翻转. 注意存在翻转超过一个周期的情况,要先取余,避免越界. 题解 class Solution {public void rotate(int[] num ...

  7. c语言中字符串去掉逗号,JS四种方法去除字符串最后的逗号

    window.οnlοad=function() { var obj = {name: "xxx", age: 30, sex: "female"};//定义一 ...

  8. java中创建数组的四种方法

    详细方法见如下四部分代码块 方法一: 详情见注释 //创建数组的第一种方法int[] arr=new int[6]; //通过创建对象的方法来声明一个数组对象int intValue=arr[5]; ...

  9. js数组去重的四种方法

    四种算法来实现这个目的: Array.prototype.unique1 = function () {var n = []; //一个新的临时数组for (var i = 0; i < thi ...

  10. php遍历数组的四种方法,PHP遍历数组的常见几种方法

    小白发博文,看到某个知识点,就当复习下. $arr=array ( 'football' =>     'well', 'swimming'=>'very well', 'run'=> ...

最新文章

  1. 64位游戏找call_替换Unity可执行文件为64位,改善游戏性能
  2. python代码覆盖率测试_unittest+coverage单元测试代码覆盖操作实例详解_python
  3. TypeScript + React 学习render props
  4. 李迟2021年12月知识总结
  5. java参数传递时,究竟传递的是什么
  6. mysql服务器的搭建_基于linux的Mysql服务器的搭建
  7. PHP+jQuery实现翻板抽奖
  8. C语言实现socket网络编程及多线程编程
  9. 图文详解Modbus-RTU协议
  10. 【报错记录】解决Shell脚本报ambiguous redirect
  11. 我的Bug日常:spark基于yarn运行时抛错,内存不足Required executor memory (1024 MB), offHeap memory (0) MB。问题已解决,亲测有用~~~
  12. 2021年中国海洋大学计算机及电子信息考研成绩分析
  13. 计算机休眠按钮是哪个,电源按钮设置成睡眠好还是休眠好?
  14. 二手车交易价格预测——数据分析
  15. 好用的数据恢复软件EasyRecovery2023最新版
  16. 翻译:Pong Game Tutorial
  17. day1 Flappy bird项目介绍
  18. H5项目常见问题及注意事项
  19. css3 烟 蚊香_如何用纯 CSS 创作一盘传统蚊香
  20. 企业微信的审批申请状态变化回调通知api接口bug

热门文章

  1. C#把excel数据转换成DataTable
  2. 商业项目计划PPT模板
  3. Unity-瓦片地图详解
  4. 一般阈值,Otsu,自适应阈值
  5. 【PP那些事儿】生产模式-面向订单生产
  6. 爱心特效代码(HTML超文本标记语言,直接改记事本后缀)
  7. cad怎么改光标样式_如何更改CAD光标大小及颜色?
  8. 应聘新要求:填写恋爱经历?
  9. unity将指定UI图片置为灰色
  10. Hash散列算法详细解析(五)