旋转数组

题目地址: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. List/Set 泛型转换

    Type typeSet = new TypeToken<Set<Long>>() {}.getType(); Type typeList = new TypeToken< ...

  2. open系统调用

    /* int open(const char *pathname, int flags, mode_t mode);flag:打开方式,可以man 2 open查看 O_RDONLY    O_WRO ...

  3. 一:JavaWeb

    1.javaWeb技术体系 2.HTMl 超文本标记语言 (超文本的意思就是除了可以包含文字之外,还可以包含图片链接音乐视频等...) 2.1 HTML网页的组成  (结构:HTML 表现:CSS 行 ...

  4. python 之路 面向对象

    ---恢复内容开始--- 一切  万物皆对象. 面向对象其实只是一种编程方式.面向对象式编程可以在很大程度上帮助我们节省时间内存,等问题是我们的代码简单明了. 那么首先定义的格式为class clas ...

  5. 一文解析TCP/UDP

    声明:本文部分内容来自互联网.书籍等渠道,表示感谢: 转载请注明出处:@热风.https://www.cnblogs.com/refeng/p/13996657.html 目录 TCP/UDP详解 1 ...

  6. HTTP介绍(一)

    超文本传输协议(HTTP)是一种用于分布式,协作式超媒体信息系统的应用程序层协议.HTTP是万维网(World Wide Web)数据通信的基础,超文本文档包括指向用户可以轻松访问的其他资源的超链接, ...

  7. 转载 数据库优化 - SQL优化

    判断问题SQL判断SQL是否有问题时可以通过两个表象进行判断: 系统级别表象CPU消耗严重IO等待严重页面响应时间过长应用的日志出现超时等错误可以使用sar命令,top命令查看当前系统状态. 也可以通 ...

  8. if __name__ == "__main__"的疑惑

    Python中if __name__ == "__main__"详细解释: 想必很多初次接触python都会见到这样一个语句,if __name__ == "__main ...

  9. Django实战总结 - 快速开发一个数据库查询工具

    一.简介 Django 是一个开放源代码的 Web 应用框架,由 Python 写成. Django 只要很少的代码就可以轻松地完成一个正式网站所需要的大部分内容,并进一步开发出全功能的 Web 服务 ...

  10. 面试必看!靠着这份字节和腾讯的面经,我成功拿下了offer!

    准备 敲定了方向和目标后就开始系统准备,主要分为以下几个方面来准备. 算法题 事先已经看过别人的社招面经知道头条每轮技术面都有算法题,而这一块平时练习的比较少,校招时刷的题也忘记了很多.因此系统复习的 ...