旋转数组

题目地址:https://leetcode-cn.com/problems/rotate-array/

给定一个数组,将数组中的元素向右移动 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]

说明:

  • 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
  • 要求使用空间复杂度为 O(1) 的 原地 算法。

题目信息

输入:数组nums、整数k

输出:修改数组(nums向右移动k位)

额外条件:空间复杂度O(1)

思考

首先想到的就是直接设置最终值,原地修改数据会丢失所以添加备份变量backup。备份值即原先值在移动时也需要与目的地数组值做交换则再需要一个中间值temp

以示例1数组演示

[1,2,3,4,5,6,7] k=3
//先原第1位移动三位到第4位
[1,2,3,1,5,6,7] backup = 4
//再移动原第4位值移动到第7位
[1,2,3,1,5,6,4] backup = 7
//再移动原第7位值移动到第3位
[1,2,7,1,5,6,4] backup = 3
//再移动原第3位值移动到第6位
[1,2,7,1,5,3,4] backup = 6
//再移动原第6位值移动到第2位
[1,6,7,1,5,3,4] backup = 2
//再移动原第2位值移动到第5位
[1,6,7,1,2,3,4] backup = 5
//再移动原第5位值移动到第1位
[5,6,7,1,2,3,4] backup = 1

最后循环到设置第一位,结束所有值移动完毕。

但这样的过程其实有个问题,并不是所有的情况都能一次循环移动所有元素。举两个例子:

示例一的情况一次循环就移动的所有元素,但上面两个例子从第一位出发到最后设置第一位完成循环但并没有设置完所有元素。一个要用两次循环一个三次。这样去使用一个中间变量去循环设值需要多少个循环取决于数组长度与k的最大公约数。

这样思路大体形成,是一个双循环。那么找到双循环的出循环条件,小循环结束条件则是下一步要移动的元素索引就是环状替换的开始索引,条件比较即使用while循环。外层循环条件两种方式都可以解决一种就是得到length与k公约数,第二种使用count计数,由于最后是数组元素全部移动所以会移动length次,小循环里每完成一次设值count累加,小循环完后来到外层循环如果count小于length则还有下一组循环。全部完成最终count是一定等于length的,出循环结束。

//这里提供一个求最大公约数的辗转相除法
int maxNumber(int m, int n) {
int temp;
if (n > m) {
temp = n;
n = m;
m = temp;
}
if (m % n == 0) {
return n;
}
return maxNumber(n, m % n);
}
public void rotate(int[] nums, int k) {
int len = nums.length;
for(int start = 0; start < maxNumber(len,k); start++){
/*
设置当前元素索引
将当前元素备份
*/
int current = start;
int backup = nums[current];
do{
//计数最终移动的索引
int next = (current + k) % len;
//当前元素原来值backup与目的地元素交换
int temp = nums[next];
nums[next] = backup;
backup = temp;
//交换完毕更新当前索引
current = next;
}while(start != current);
}
}

上面外循环以公约数为条件即已知循环次数完成,下面使用count在小循环里计数在外循环判断完成

方式一

public void rotate(int[] nums, int k) {
int count = 0;
int len = nums.length;
for(int start = 0; count < len; start++){
int current = start;
int backup = nums[current];
do{
int next = (current + k) % len;
int temp = nums[next];
nums[next] = backup;
backup = temp;
current = next;
count++;
}while(start != current);
}
}

这样环状替换的解决方式是最先想到的,还有一种方式看题目示例就可以get到这个方向。也就是解决整体移动一次的逻辑,接下来就是循环就完了。整体移动一次时间复杂度就为n然后完成n次。比上面的算法就复杂度来看差一些。完成整体移动一次使用交换法即可(用备份值方式仅仅多了变量不会影响时间复杂度)。

//每次使用最后位与i位进行交换,i++
[1,2,3,4,5] 1<==>5
[5,2,3,4,1] 2<==>1
[5,1,3,4,2] 3<==>2
[5,1,2,4,3] 4<==>3
[5,1,2,3,4]
for (int j = 0; j < len; j++) {
temp = nums[j];
nums[j] = nums[len-1];
nums[len-1] = temp;
}

那么有了这样一个移动一次的代码,再结合K外层循环

方式二

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

最后还有一个反转法,跳开设置值的思路,通过别的算法组合也能达到目标情况,在初高中数学当中也是常常有知道一个式子的值求一个很长的式子而不用把第一个式子解开而是将最终式子化成已知式子的组合最终简单求解。在这里也是一样一个反转算法这样的算法很简单

while (i < j) {
int temp = nums[i];
nums[1] = nums[j];
nums[j] = temp;
i++;
j--;
}

观察我们的要得到的一个结果

//nums = [1 2 3 4 5 6], k=3
1 2 3 4 5 6
4 5 6 1 2 3

可以通过反转的组合实现

1 2 3 4 5 6
6 5 4 3 2 1 全反转
4 5 6 3 2 1 0到k-1反转
4 5 6 1 2 3 k到len-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--;
}
} 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);
}

LeetCode初级算法之数组:189 旋转数组的更多相关文章

  1. LeetCode初级算法--数组02:旋转数组

    LeetCode初级算法--数组02:旋转数组 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/ ...

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

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

  3. LeetCode初级算法的Python实现--数组

    LeetCode初级算法的Python实现--数组 # -*- coding: utf-8 -*- """ @Created on 2018/6/3 17:06 @aut ...

  4. 【Leetcode】【简单】【189. 旋转数组】【JavaScript】

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

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

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

  6. LeetCode初级算法之数组:48 旋转图像

    旋转图像 题目地址:https://leetcode-cn.com/problems/rotate-image/ 给定一个 n × n 的二维矩阵表示一个图像. 将图像顺时针旋转 90 度. 说明: ...

  7. LeetCode初级算法(数组)解答

    这里记录了LeetCode初级算法中数组的一些题目: 加一 本来想先转成整数,加1后再转回去:耽美想到测试的例子考虑到了这个方法的笨重,所以int类型超了最大范围65536,导致程序出错. class ...

  8. LeetCode初级算法--数组01:只出现一次的数字

    LeetCode初级算法--数组01:只出现一次的数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...

  9. LeetCode初级算法--设计问题01:Shuffle an Array (打乱数组)

    LeetCode初级算法--设计问题01:Shuffle an Array (打乱数组) 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:h ...

  10. Java实现 LeetCode 189 旋转数组

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

随机推荐

  1. 四、API Gateway相关------微服务构架设计模式

  2. TCP/IP模型简介和/etc/hosts文件说明

    软件=协议的实现. IP决定了主机的位置.端口号决定了进程的位置. 两台主机上的通讯实际是两台主机上两个具体进程的通讯. TCP/IP模型分四层: TCP/IP模型:应用层---传输层----网络层- ...

  3. Adaboost算法的一个简单实现——基于《统计学习方法(李航)》第八章

    最近阅读了李航的<统计学习方法(第二版)>,对AdaBoost算法进行了学习. 在第八章的8.1.3小节中,举了一个具体的算法计算实例.美中不足的是书上只给出了数值解,这里用代码将它实现一 ...

  4. 一篇文章了解_docker

    (一)Docker介绍 2018年10月6日 星期六 15:04 什么就Docker? Docker是一个开源项目, 诞生于2013年初,最初是dotCloud公司内部的一个业余项目.它基于Googl ...

  5. 为什么说线程太多,cpu切换线程会浪费很多时间?

    问题1: 假如有一个计算任务,计算1-100的和,每10个数相加,需要占用一个cpu时间片(1s).如果起一个线程(模拟没有线程切换),完成任务需要多长时间?如果起5个线程,完成任务需要消耗多久时间? ...

  6. 创建Spring Cloud聚合项目

    使用maven创建单一项目的时候通常用不到聚合项目,创建spring cloud项目时候,由于下面都是一个一个微服务,每个服务对应一个项目,这就需要用到聚合项目,方便对依赖和项目之间的关系进行管理,使 ...

  7. mysql学习笔记1(mysql的基本架构)

    mysql基本架构图 如图所示: 1 . MySQL 可以分为 Server 层和存储引擎层两部分 Server 层包括连接器.查询缓存.分析器.优化器.执行器等,涵盖 MySQL 的大多数核心服务功 ...

  8. 讲一讲Java的字符串常量池,看完你的思路就清晰了

    前言 很多朋友Java的字符串常量池的概念困扰了很长一段时间,最近研究了一下jvm指令码,终于对它有了大概的了解. 在展示案例前,我们需要先搞清楚一个概念,众所周知,jvm的内存模型由程序计数器.虚拟 ...

  9. 万字长文带你掌握Java数组与排序,代码实现原理都帮你搞明白!

    查找元素索引位置 基本查找 根据数组元素找出该元素第一次在数组中出现的索引 public class TestArray1 { public static void main(String[] arg ...

  10. 打开WPS时出现MathType错误弹窗怎么办

    MathType是一款特别优秀的公式编辑器,特别是在文档中出现大量的复杂数学公式需要编辑时.不过MathType与Office的兼容性还算好,与WPS的兼容性要略逊一筹,有时候会出现如下的报错弹窗.提 ...