我正在解决这个问题
给定一组数字,我需要在结尾处移动全零 数组(就地而不制作数组副本)
例如:给定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
);为什么?我该如何解决?
答案 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,如下所示:
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;
答案 1 :(得分:2)
就地解决方案:为了向右移动所有零,我们遍历数组,跟踪最后一个非零元素的索引i
并转移所有左边的非零元素:
// 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;
说明:我们从i
和j
开始,指向第一个数组元素。
现在我们从左到右遍历数组元素。每当我们遇到零时,我们只会增加j
而不是i
。
因此,i
和j
之间的差异等于数组中的零到j
的数量。现在的诀窍是:为了向右移动零,我们实际上需要将所有非零移动到左侧。左边多少钱?到目前为止我们遇到的零的数量正是如此。这是由array[i] = array[j]
完成的。最后,i
的最后一个非零元素与结尾之间的剩余空格用零填充。
两个操作 - 交换值和填充零 - 都是就地执行的,而拼接和推送通常不会就地考虑,因为它们会改变数组大小和可能的内存位置。
答案 2 :(得分:1)
索引不会更新。
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;
答案 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
函数的一种方法:
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;
如果你只想循环一次数组,你可以这样做:
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;