前言
最近身体很差,浑身疼,脱发严重,长痘痘,唉。。。
要认真学习,好好找工作啊,每天的任务不能怠慢。
今日题目
leecode189: leecode189.旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 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]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 向右旋转 1 步: [99,-1,-100,3] 向右旋转 2 步: [3,99,-1,-100]
解题思路
思路一:使用额外的数组
这是看到题目第一个想到的方法,也是相对简单的方法。
创建一个新数组,遍历原数组,将数组元素放到指定的位置即可
var rotate = function(nums, k) {
const length = nums.length
const result = []
for(let i = 0; i < length; i++) {
result[(k + i) % length] = nums[i]
}
for(let i = 0; i < length; i++) {
nums[i] = result[i]
}
return nums
};
由于创建了新的数组,并等于原数组长度,所以空间复杂度是O(n)
遍历了两次数组,时间复杂度O(n)
思路二: 数组翻转
将数组向右移动k位,得到的数组k % length的尾部元素被移动到头部,剩下的元素向后移动
将原数组全部翻转
再将前k个元素翻转
再将后length-k元素翻转
经过三次翻转后得到目标数组
var rotate = function(nums, k) {
k %= nums.length;
reverse(nums, 0, nums.length);
reverse(nums, 0, k);
reverse(nums, k, nums.length);
};
function reverse(nums, begin, end) {
var left = begin;
var right = end - 1;
while(left < right) {
var temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left += 1;
right -= 1;
}
}
思路三: 循环移位算法
对于一个长度为n的数组,整体移动k位
如果n和k的最大公约数是1, 代表1次循环就可以交换完成,n= 7 k=3 最大公约数为1
如果n和k的最大公约数大于1, 需要最大公约数次循环可以交换完成,n=6 k=4 最大公约数是2
如下是k=3, n=7的情况,1次循环就结束
如下是k=4, n=6的情况,2次循环结束
const gcd = (x, y) => y ? gcd(y, x % y) : x;
var rotate = function(nums, k) {
const n = nums.length;
k = k % n;
let count = gcd(k, n);
for (let start = 0; start < count; ++start) {
let current = start;
let prev = nums[start];
do {
const next = (current + k) % n;
const temp = nums[next];
nums[next] = prev;
prev = temp;
current = next;
} while (start !== current);
}
}
总结
本题使用了三种算法解决问题,循环移位方法和数组翻转方法在字符串的题目中也经常遇到,理解花了一些时间,但是搞懂了对其他题目是有很大帮助的。
这次题解写了大半天的时间, 要滚去干活咯。。。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情