前言:
最近由于工作较忙,练习的频率有点低了,以后尽量保持两到三天练习一道的频率和效率。
那么开始这一次算法练习。
题目描述:
给定一个数组,将数组中的元素向右移动 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) 的 原地 算法。
解题思路:
看到题目我首先注意到了要使用空间复杂度为O(1)的原地算法,那么我们就不能再创建新的数组来作为辅助,所以我想到的是利用元素替换的方法,但是想了很久没有成功解决,所以就想先借助额外的数组空间来解决(虽然是不满足题意的)。
方案1(不满足题意):
let length=array.length;
let realK=k%length;
let index=length-realK;
for(let i=0;i<length;i++){
if(index<length){
array.push(array[index]);
}else {
array.push(array[index-length])
}
index++;
}
array.splice(0,length);
console.log(array);
这种方法是不满足题意的,因为使用了额外的数组空间。不过也讲一下解题思路,首先我们假设数组平移之后是下面这样的。
//原数组
[1,2,3,4,5]
//平移后的数组k=2
[4,5,1,2,3]
//我们发现数组平移后k指针之后的元素,我们把数组从k开始依次放入原数组,得到一个新数组
[1,2,3,4,5,4,5,1,2,3]
//最后截取原数组长度数组得到答案
[4,5,1,2,3]
上面的思路是很容易理解的,但是是不满足题意的,所以我继续想新的解决方案,我想到了将这个问题分解来解决,首先我们实现将数组移动一位的算法,那么之后循环k就可以解决,所以解决方案二如下。
方案二:
//缓存被替换的元素
let buffer=null;
//计算真实的k值
k=k%nums.length;
//移动k位
while (k>0){
/*移动一位的算法*/
for(let i=0;i<nums.length;i++){
//指针越界之后的处理
if(i+1>=nums.length){
let index=i+1-nums.length;
nums[index]=buffer;
}else{
//首次遍历时buffer为null
if(buffer==null)
//先保存要替换的元素的值
buffer=nums[i+1];
nums[i+1]=nums[i];
}else{
//for局部变量保存要替换的元素
let b=nums[i+1];
//给元素赋值上一次循环缓存的值
nums[i+1]=buffer;
//函数全局变量保存要替换的元素
buffer=b;
}
}
}
k--;
}
这种方法可以说满足了题意,但是执行时间十分长,到该500-600ms,因为会循环执行很多次。所以我们提交答案之后就不厚道的去看了别人的答案=。=。
看到一个这样的解法:
方案三:
let length=array.length;
let realK=k%length;
for(let i=0;i<realK;i++){
let num=nums.pop();
nums.unshift(num);
}
console.log(nums);
代码逻辑很清晰,就是讲数组的最后一个元素pop出来,再使用unshift插入到数组的最前面即可 。
实际上我的第一种方案已经接近这个答案了,但是因为我不熟悉数组的api,pop、unshift、splice等,所以我都不知道js数组可以在数组的最前面(unshift)或者指定位置(使用splice)插入元素。
总结:
首先我感觉我还是不能把锅甩给不了解js数组的api,主要原因还是解题思路有问题。
如果我首先想到这个平移问题的本质是将最后一个元素取出,放到数组的前端,依次类推,那么我一定会去想办法找数组插入的方法,即使不知道unshift方法,使用我已知的splice方法也可以实现。
其次,我认为自己对数据结构的学习或者说理解不够,我认为是可以想成队列的数据结构的问题,如果一开始把这个数组结构想成是一个队列,平移操作想成是出队列再入队列即可解决这个问题。
综上所述,总结两点
1、复杂问题(虽然方法对了的话并不复杂=。=),学会将问题分解为单个简单操作;
2、要去复习一下数据结构的知识了!