资讯专栏INFORMATION COLUMN

leetcode刷题:283.Move Zeroes(Easy)

ckllj / 666人阅读

摘要:解法目的就是把一个数组中所有为的数移动到数组的尾部,并保证其他元素相对位置不变。要求是在原数组上修改,不要额外引入其他的数组尽量减少操作次数。在小游戏中,设置了和界面一致的二维数组,数组的每一位记录了一个数字。

地址:https://leetcode.com/problems/move-zeroes/

应用场景说明

这个题是很Easy的一道题,它的应用场景是在我尝试写小游戏2048时,采用了二维数组存放数字占位,当按上下左右键时,要把所有的数字靠在一边,而所有为0的靠在另一边,这时候用到这个题的解题思路很快能做出来。

解法

目的就是把一个数组中所有为0的数移动到数组的尾部,并保证其他元素相对位置不变。要求是在原数组上修改,不要额外引入其他的数组;尽量减少操作次数。

输入:

[0,1,0,3,12]

输出

[1,3,12,0,0]

首先先引入额外数组的方式看如何来写:

var moveZeroes = function(nums) {
    let nonZeroArr = [];  // 用来存放非0元素
    for(let i = 0; i < nums.length; i++) {
      if(nums[i]){
        nonZeroArr.push(nums[i])
      }
    }
    // 把新数组中的每一项对位的赋值给原数组
    for(let j = 0; j < nonZeroArr.length; j++){
      nums[j] = nonZeroArr[j]
    }

    // 把nums中之后的位置都补上0
    for(let k = nonZeroArr.length; k < nums.length; k++){
      nums[k] = 0;
    }
    
    return nums;
};

let arr = [0,1,0,3,0,9,0,12];

console.log(moveZeroes(arr)); // [ 1, 3, 9, 12, 0, 0, 0, 0 ]

思路很简单,就是把不为0的数字存在一个新数组中,把新数组的每一项对位的重新赋值给原来数组的位置,然后把原数组剩余的位置一律替换为0;

这样的写法在时间复杂度上是 O(n) 级别的,在空间复杂度上也是O(n) 级别的,因为引入了新的数组。

可以在不引入新数组的情况下做位置的调整:

var moveZeroes = function(nums) {
  let lastZeroIndex = 0;  // 每一次最后找到的0的位置,初始是0
  for(let i = 0; i < nums.length; i++){
    if(nums[i]) {  // 不为0
      nums[lastZeroIndex++] = nums[i];  // 把遍历到不为0的数字,替换在0的位置,替换的位置已经不是0了,向后推一步;
    }
  }
  // 从k的位置开始之后的都应该为0
  while(lastZeroIndex < nums.length){
    nums[lastZeroIndex++] = 0;
  }
  return nums;
};

let arr = [0,1,0,3,0,9,0,12];
console.log(moveZeroes(arr)); // [ 1, 3, 9, 12, 0, 0, 0, 0 ]

以上的做法只在一个数组中操作,用变量 repalceIndex 存一下要被非零数字替换的位置。在遍历中遇到了非0数字,则替换在 repalceIndex的位置,再将repalceIndex向后推一位,等待下一次遇到非零数字来替换,等到遍历结束,repalceIndex 实际上就是非零数字的个数,再从这个位置开始直到数组结束都替换为0。

这样的写法在时间复杂度上是 O(n) 级别的,在空间复杂度上也是O(1) 级别的,因为没有引入了新的数组。

这样还不是最终答案,因为在最后还需要一个 for 循环将剩下的位置都替换为0,多了一步这样的操作是没必要的。

下面采用交换位置的方式。

var moveZeroes = function(nums) {
  let repalceIndex = 0;  // 记录要被交换的位置
  let replaceElement; // 中间变量,用来存不为0的数字
  for(let i = 0; i < nums.length; i++){
    if(nums[i]) {  // 当不为0
      if(i != repalceIndex) {  // 第i个和repalceIndex相同,说明要交换的是同一个元素,没必要进行交换操作
        replaceElement = nums[i];
        nums[i] = 0;
        nums[repalceIndex] = replaceElement;
      }
      repalceIndex++
    }
  }
  
  return nums;
};
let arr = [0,1,0,3,0,9,0,12];
console.log(moveZeroes(arr)); // [ 1, 3, 9, 12, 0, 0, 0, 0 ]

上面的思路是这样的,repalceIndex 记录了第一个是0的位置,当遇到非0的数字时候,就把非0的数字和repalceIndex所在位置的0交换位置,然后 repalceIndex 向前推进一位,继续记录的还是第一个0的位置,遍历中再与非0数字交换,再推进。。。重复这个过程直到遍历结束。
判断 i != repalceIndex 是一种优化手段,只有非0位置的数字和要交换的位置不是同一个位置才进行交换。

我自己在写小游戏2048的时候用到了这个题的解题思路。在小游戏2048中,设置了和界面一致的二维数组,数组的每一位记录了一个数字。

尝试用在小游戏2048中

我在写2048小游戏时,数据存放的是一个 4X4 的二维数组(当然有很多的做法,可以采用别的方式),例如这样:

let data = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]

这些0都是占位的,代表的是还未填充任何数据,随着玩家玩的过程,会出现很多数字分散在不同的位置上,当按上下左右时,总要把所有不为0的数字拨在同一边,0的数字在另一边,这时就用到上述这个题的解法即可。

let data = [
    [2, 0, 0, 0],
    [0, 4, 0, 0],
    [0, 0, 2, 4],
    [0, 2, 2, 0]
]
// 遍历取出每一个数组
for(let i = 0; i < data.length; i++){
    moveZeroes(data[i])
}

如果掌握了上述的技巧,无论是向左向右还是向上向下都可以做到。

后记

在刚开始尝试解这道题时,心里在想,出这道题的人是有多无聊,只是为了创造问题而创造,压根想不到这道题的应用场景在哪里,这也跟自己的眼界有关系。当我在尝试做2048小游戏时,设计出来存放数据结构后,开始实现自己要实现的方式时,才意识到原来这么简单的一道题不是没有场景,而是自己没遇到,当遇到时豁然开朗。

这也给了我一个启示,任何一道题存在必然是有原因的,它就是解决了某一个问题而存在的,当我有了这样的意识,在做每一道题的时候,会多问自己一下,这道题的应用场景在哪里,我现在做的项目中有没有类似的场景可以套用,如果没有,去找一种案例应用在场景中,这样刷完提后不至于很快忘记,只要记住了案例,刷的题也自然而然的记住了。

以上如有偏差欢迎指正学习,谢谢。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101523.html

相关文章

  • Leetcode PHP题解--D68 283. Move Zeroes

    摘要:题目链接题目分析给定一个整数数组,将值为的元素移动到数组末尾,而不改动其他元素出现的顺序。再在去后的元素末尾填充到计算出的数组长度。最终代码若觉得本文章对你有用,欢迎用爱发电资助。 D68 283. Move Zeroes 题目链接 283. Move Zeroes 题目分析 给定一个整数数组,将值为0的元素移动到数组末尾,而不改动其他元素出现的顺序。 思路 计算总共有多少个元素。 再...

    xiongzenghui 评论0 收藏0
  • leetcode 283 Move Zeroes

    题目详情 Given an array nums, write a function to move all 0s to the end of it while maintaining the relative order of the non-zero elements.For example, given nums = [0, 1, 0, 3, 12], after calling your ...

    RobinQu 评论0 收藏0
  • leetcode 部分解答索引(持续更新~)

    摘要:前言从开始写相关的博客到现在也蛮多篇了。而且当时也没有按顺序写现在翻起来觉得蛮乱的。可能大家看着也非常不方便。所以在这里做个索引嘻嘻。顺序整理更新更新更新更新更新更新更新更新更新更新更新更新更新更新更新更新 前言 从开始写leetcode相关的博客到现在也蛮多篇了。而且当时也没有按顺序写~现在翻起来觉得蛮乱的。可能大家看着也非常不方便。所以在这里做个索引嘻嘻。 顺序整理 1~50 1...

    leo108 评论0 收藏0
  • LeetCode 攻略 - 2019 年 8 月上半月汇总(109 题攻略)

    摘要:每天会折腾一道及以上题目,并将其解题思路记录成文章,发布到和微信公众号上。三汇总返回目录在月日月日这半个月中,做了汇总了数组知识点。或者拉到本文最下面,添加的微信等会根据题解以及留言内容,进行补充,并添加上提供题解的小伙伴的昵称和地址。 LeetCode 汇总 - 2019/08/15 Create by jsliang on 2019-08-12 19:39:34 Recently...

    tracy 评论0 收藏0
  • 前端 | 每天一个 LeetCode

    摘要:在线网站地址我的微信公众号完整题目列表从年月日起,每天更新一题,顺序从易到难,目前已更新个题。这是项目地址欢迎一起交流学习。 这篇文章记录我练习的 LeetCode 题目,语言 JavaScript。 在线网站:https://cattle.w3fun.com GitHub 地址:https://github.com/swpuLeo/ca...我的微信公众号: showImg(htt...

    张汉庆 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<