话说最近嘀起心肝(下定决心)练习算法, 虽说大学也学过算法, 但是当时觉得犹如天书并差点挂科, 此时又是算法大热门时代(各大中厂的敲门砖), 于是乎给自己定下了一个小目标, 跟着leetcode学算法, 并在此记录一些总结, 尽量把自己理解的过程写出来,便于参考回顾
leetcode的链接地址是leetcode-cn.com/
今天这道题如下:
一看到题目, 第一个想到的方法就是数组的操作方法splice和push, 于是一顿简单粗暴
var moveZeroes = function(nums) {
var length = nums.length
var i= 0
while(i<length) {
if(nums[i] === 0) {
// 从头遍历一次,把非0的剪出来, 再push进去数组尾部,同时遍历长度-1 (因为后面的已经全是0了,就没必要重复遍历了)
nums.splice(i,1)
nums.push(0)
length--
} else {
i++
}
}
}
提交看看
What??? 用时312ms? 才打败10.25%用户? (不得不为leetcode的这个功能点赞,成功地引起了我的胜负欲)
于是继续思考, 是不是可以用嵌套遍历的方法,把遇到的0跟后面的第一个非0数值调换顺序,一顿敲
var moveZeroes = function(nums) {
var length = nums.length
for(var i=0; i<length-1;i++) {
// 遇到0就处理(往后找非0), 遇到非0就跳过
if(nums[i] === 0) {
for(var j=i+1;j<length;j++) {
// 我要找的是非0,所以后面是0的时候也跳过,不跟你换
if(nums[j] === 0) continue;
// 非0就跟外层循环中找到的0调换,并且跳出内层for循环,继续在外层for循环中继续找0
var temp = nums[j]
nums[j] = nums[i]
nums[i] = temp
break;
}
}
}
}
行了提交看看
稍微有进步,但是感觉应该会有更优的方法(当你苦思冥想想不出来的时候,就去参考一下别人的解决方案吧,何必难为自己)
找到了,Oh,双指针,我也想过,但是思路不算很清晰,参考后一敲一试
//left始终指向第一个0, right每一轮都+1,找到一个非0就跟left上的元素交换,让非0元素往前挪,然后left+1(left是否往前走取决于right的检测结果)
var moveZeroes = function(nums) {
var length = nums.length,left=0,right=0;
while(right<length) {
if(nums[right]) {
var temp = nums[left]
nums[left] = nums[right]
nums[right] = temp
left++
}
right++
}
}
wow,执行用时666👍,但是这个思路其实不是很好理解(为啥都从0开始,为啥判断nums[r]??), 所以我就试着在纸上用一个简单的示例演算了一下, 豁然开朗! 好思路不如烂笔头!
nice~
小总结:
对比上面几个算法, 基本上很少有空间和时间都最优的解法, 要么就是空间换时间, 要么是时间换空间, 具体问题具体分析
有更棒的解法欢迎交流, 共同进步!