[关闭]
@wy 2019-02-01T21:31:05.000000Z 字数 1965 阅读 556

leetcode刷题:283.Move Zeroes(Easy)

javascript


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


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

输入:

[0,1,0,3,12]

输出

[1,3,12,0,0]

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

  1. var moveZeroes = function(nums) {
  2. let nonZeroArr = []; // 用来存放非0元素
  3. for(let i = 0; i < nums.length; i++) {
  4. if(nums[i]){
  5. nonZeroArr.push(nums[i])
  6. }
  7. }
  8. // 把新数组中的每一项对位的赋值给原数组
  9. for(let j = 0; j < nonZeroArr.length; j++){
  10. nums[j] = nonZeroArr[j]
  11. }
  12. // 把nums中之后的位置都补上0
  13. for(let k = nonZeroArr.length; k < nums.length; k++){
  14. nums[k] = 0;
  15. }
  16. return nums;
  17. };
  18. let arr = [0,1,0,3,0,9,0,12];
  19. console.log(moveZeroes(arr)); // [ 1, 3, 9, 12, 0, 0, 0, 0 ]

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

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

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

  1. var moveZeroes = function(nums) {
  2. let lastZeroIndex = 0; // 每一次最后找到的0的位置,初始是0
  3. for(let i = 0; i < nums.length; i++){
  4. if(nums[i]) { // 不为0
  5. nums[lastZeroIndex++] = nums[i]; // 把遍历到不为0的数字,替换在0的位置,替换的位置已经不是0了,向后推一步;
  6. }
  7. }
  8. // 从k的位置开始之后的都应该为0
  9. while(lastZeroIndex < nums.length){
  10. nums[lastZeroIndex++] = 0;
  11. }
  12. return nums;
  13. };
  14. let arr = [0,1,0,3,0,9,0,12];
  15. console.log(moveZeroes(arr)); // [ 1, 3, 9, 12, 0, 0, 0, 0 ]

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

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

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

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

  1. var moveZeroes = function(nums) {
  2. let repalceIndex = 0; // 记录要被交换的位置
  3. let replaceElement; // 中间变量,用来存不为0的数字
  4. for(let i = 0; i < nums.length; i++){
  5. if(nums[i]) { // 当不为0
  6. if(i != repalceIndex) { // 第i个和repalceIndex相同,说明要交换的是同一个元素,没必要进行交换操作
  7. replaceElement = nums[i];
  8. nums[i] = 0;
  9. nums[repalceIndex] = replaceElement;
  10. }
  11. repalceIndex++
  12. }
  13. }
  14. return nums;
  15. };
  16. let arr = [0,1,0,3,0,9,0,12];
  17. 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中,设置了和界面一致的二维数组,数组的每一位记录了一个数字。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注