Javascript数组在末尾附加0

时间:2017-03-18 00:35:21

标签: javascript

我正在解决这个问题

  

给定一组数字,我需要在结尾处移动全零   数组(就地而不制作数组副本)

     

例如:给定nums = [0,1,0,3,12]

     打电话给你后   功能,nums应为[1,3,12,0,0]。

我的尝试:

   var moveZeroes = function(nums) {
      var count=0;
      
      //Remove anything that's not Zero.
      nums.forEach(function(val, index){
        if(val==0){
          nums.splice(index, 1);
          count++;
        }
      });
    
      //Fill in Zeros at the end
      for(var i=0; i< count ; i++){
        nums.push(0);
      }
    };
    
    
    var input1 = [0,1,0,3,12];
    var input2 = [0,0,1];
    
    moveZeroes(input1)
    console.log(input1); //Works!
    
    moveZeroes(input2)
    console.log(input2); //fails!

问题:

它适用于[0,1,0,3,12]之类的输入,但输入失败,例如[0,0,1](我得到的输出是0,1,0);为什么?我该如何解决?

7 个答案:

答案 0 :(得分:2)

你正在从你正在循环的数组中切出(splicing)(在forEach中),因此有更多的连续0将跳过其中的一些

因此,如果数组为[0, 0, 1],则会发生以下情况:

forEach: (case of two or more successive 0s)

    [0, 0, 1]
//   ^ cursor is here (0 === 0 then remove it)
    [0, 1]
//      ^ cursor is at the second item, the second 0 is safe because it is now occupy a place that is already looped over
    [0, 1]
// fails

forEach: (case of no successive 0s)

    [0, 1, 0, 1]
//   ^ cursor is here (0 === 0 then remove it)
    [1, 0, 1]
//      ^ (0 === 0 then remove) 
    [1, 1]
// works

要解决这个问题,你必须使用一个基本的for循环,在那里你可以控制光标的位置(索引),或者以一种改变它的方式改变数组&#39 ; s长度并没有隐藏在光标后面的0,如下所示:

&#13;
&#13;
var moveZeroes = function(nums) {
  nums.forEach(function(val, index) {
    if (val) {               // if it is a non-zero value
      nums.splice(index, 1); // remove it
      nums.unshift(val);     // add it to the begining of the array (note that the order of non-zero values will be reversed)
    }
  });
};


var input1 = [0, 1, 0, 3, 12];
var input2 = [0, 0, 1];

moveZeroes(input1)
console.log(input1); //Works!

moveZeroes(input2)
console.log(input2); // Now Works too!
&#13;
&#13;
&#13;

答案 1 :(得分:2)

就地解决方案:为了向右移动所有零,我们遍历数组,跟踪最后一个非零元素的索引i并转移所有左边的非零元素:

&#13;
&#13;
// Moves zeroes to the right:
function moveZeroes(array) {
  let i = 0;
  for (let j = 0; j < array.length; ++j) {
    if (i < j) array[i] = array[j];
    if (array[j] != 0) ++i;
  }
  return array.fill(0, i);
}

// Example:
console.log(moveZeroes([0, 1, 0, 3, 12]));
&#13;
&#13;
&#13;

说明:我们从ij开始,指向第一个数组元素。 现在我们从左到右遍历数组元素。每当我们遇到零时,我们只会增加j而不是i。 因此,ij之间的差异等于数组中的零到j的数量。现在的诀窍是:为了向右移动零,我们实际上需要将所有非零移动到左侧。左边多少钱?到目前为止我们遇到的零的数量正是如此。这是由array[i] = array[j]完成的。最后,i的最后一个非零元素与结尾之间的剩余空格用零填充。

两个操作 - 交换值和填充零 - 都是就地执行的,而拼接和推送通常不会就地考虑,因为它们会改变数组大小和可能的内存位置。

答案 2 :(得分:1)

删除array.use中的项目时,

索引不会更新。

&#13;
&#13;
var moveZeroes = function(nums) {
  var count=0;

  //Remove anything that's not Zero.
  for(var index=0;index<nums.length;index++){     
    if(nums[index]==0){
      //when remove item from the array,the rest items index after removed item changed.
     //so you must change the index variable in the loop via:index--.
      nums.splice(index--, 1);
      count++;
    }
  };

  //Fill in Zeros at the end
  for(var i=0; i< count ; i++){
    nums.push(0);
  }
};


var input1 = [0,1,0,3,12];
var input2 = [0,0,1];

moveZeroes(input1)
console.log(input1); //Works!

moveZeroes(input2)
console.log(input2); //Works too!
&#13;
&#13;
&#13;

答案 3 :(得分:1)

如果您有兴趣,可以使用其他实现方法。 用一个简单的for循环

var moveZeroes = function(nums) {
     var res = []
     var count=0
     for(var i = 0 ; i < nums.length ; i++){
        nums[i] == 0 ? count += 1 : res.push(nums[i])
     }

    for(var j = 0 ; j < count ; j++){
      res.push(0)
    }

    return res
};


    var input1 = [0,1,0,3,12];
    var input2 = [0,0,1];

    console.log(moveZeroes(input1))

    console.log(moveZeroes(input2))

答案 4 :(得分:0)

我想我明白了。无论何时我们做什么&#34; Splice&#34;我们正在改变数组大小,因此在第二个例子中,我们还需要检查前一个元素。

完成的代码如下:

var moveZeroes = function(nums) {
  var count=0;

  nums.forEach(function(val, index){
    if(val==0){
      nums.splice(index, 1);
      count++;
    }

    if(nums[index-1] == 0){
        nums.splice(index-1, 1);
        count++;
    }
  });

  for(var i=0; i< count ; i++){
    nums.push(0);
  }
};

答案 5 :(得分:0)

问题是你在循环时修改数组。每次拼接出一个元素时,它后面的所有元素都会向下移动。但是下一次迭代会转到下一个元素,因此它会跳过移动到已删除元素位置的元素。第一个示例似乎有效,因为数组中的行中没有两个0,因此跳过下一个元素不会导致问题。第二个示例连续有两个0,因此它会跳过该对中的第二个。

解决这类问题的最简单方法是反向迭代。

var moveZeroes = function(nums) {
      for (var i = nums.length-1; i >= 0; i--) {
        if (nums[i] == 0) {
          nums.splice(i, 1);
          nums.push(0);
        }
      }
    };
    
    
    var input1 = [0,1,0,3,12];
    var input2 = [0,0,1];
    
    moveZeroes(input1)
    console.log(input1); //Works!
    
    moveZeroes(input2)
    console.log(input2); //fails!

答案 6 :(得分:0)

正如其他人已经提到的那样,您正在从正在迭代的数组中删除元素。这会导致forEach函数中提供的索引(即迭代原始版本的数组)超出当前更新数组的日期。

以下是使用filter函数的一种方法:

&#13;
&#13;
var moveZeroesToEnd = function(nums) {
  var nonZeros = nums.filter(function(num) {
    return num != 0;
  });
  var zeros = nums.filter(function(num) {
    return num == 0;
  });
  return nonZeros.concat(zeros);
};


var input1 = [0, 1, 0, 3, 12];
var input2 = [0, 0, 1];

console.log(moveZeroesToEnd(input1))

console.log(moveZeroesToEnd(input2));
&#13;
&#13;
&#13;

如果你只想循环一次数组,你可以这样做:

&#13;
&#13;
var moveZeroesToEnd = function(nums) {
  var nonZeros = [];
  var zeros = [];
  nums.forEach(function(num) {
    var arr = num ? nonZeros : zeros;
    arr.push(num);
  });
  return nonZeros.concat(zeros);
};


var input1 = [0, 1, 0, 3, 12];
var input2 = [0, 0, 1];

console.log(moveZeroesToEnd(input1))

console.log(moveZeroesToEnd(input2));
&#13;
&#13;
&#13;