第 82 题:算法题「移动零」,给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(51)
原地交换,没有用多余的数组。应该是O(n)。
木有上面大佬的简洁,不知道能不能覆盖所有情况,求指正
这个我在 chrome 上试的时候无法排序,在 safari 上倒是可以按照逻辑输出 @wz71014q
还用上面的方法的话,如果元素为0,可以把正在循环的索引减 1
const array = [0, 2, 0, 1, 4, 0, 0, 0, 5, 7, 8];
array.sort((fir, sec) => {
return (fir === 0) ? 1 : -1
})
这样试试?
可以了,谢啦 @lo1412
clock in
思路:
@kingstone3 我用node运行的是可以,后面放到chrome果然结果不一样。。。没有safari。。。没有试具体结果
var arr = [0, 1, 0, 3, 12];
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] == 0) {
arr.splice(i, 1);
arr.push(0)
}
}
@tanggd
阁下觉得我的写法怎么样
流下没有技术的眼泪
arr.sort((a,b) => { if(Math.abs(a-b) == (a +b)){return b-a}})
发现是零,continue,否则就填充数组,最后补零;

const moveZeros = (nums: number[]): number[] => {
return moveZerosR(nums, 0, nums.length - 1)
}
const moveZerosR = (nums: number[], l: number, r: number): number[] => {
if (l > r) return
const top = nums.shift()
if (top === 0) {
return [...moveZerosR(nums, l + 1, r), top]
} else {
return [top, ...moveZerosR(nums, l + 1, r)]
}
}
let arr = [3, -2, 341, 4, 0, 0, 3, 531, 0, 0, 0, 13, 53]
function roll(arr) {
let i = 0, j = arr.length - 1;
while (i < j) {
if (arr[i] === 0) {
swap(arr, i, j);
j--;
}
i++
}
return arr
}
function swap(arr, i, j) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp
}
console.log(roll(arr));
双指针,空间、时间复杂度都是最优
function move (arr) { let k = arr.length - 1 while (k >= 0) { if (arr[k] === 0) { arr.push(arr.splice(k, 1)[0]) } k-- } return arr }
利用排序,非0之间相等,0比非0大
function sort(arr){
let i=0;
let j=arr.length-1;
while(i<j){
while(arr[i]!==0){
i++;
}
while(arr[j]==0){
j--;
}
if(i<j){
let tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
}
return arr;
}
上面所有的再循环中,先 splice 在 push 的方法都是有问题的
因为,当
splice
一个元素的时候,紧跟着的后面一个元素会向前移动一位,索引会变成正在删除那个元素的,所有当有连续的 0 时候,无法满足要求let moveZero = (arr) => {
let point = 0
for (var i = 0; i < arr.length; i++) {
if (arr[i]!=0) {
arr[point] = arr[i]
arr[i] = 0
point++
}
}
return arr
}
最优解法
想到好几个方法,楼上都写出来了,但是我觉得这些都不是最优解法,既然是算法题,自然是以算法的思维去解。
那个这个问题怎么解决?没头绪
为什么倒序可以解决这个办法
因为待处理的数据索引没有变。https://www.jianshu.com/p/77247e9e1849
原地
修改数组,那么sort,concat之类的纯函数方法就是行不通的了,因为是返回新的数组,而不是在原地修改思路:双指针
时间复杂度O(n),n是数组长度,空间复杂度O(1)
思路是把0剔除出来,然后再塞进去- -
let or = [0, 1, 0, 3, 12]
let len = or.length
while (len) {
if(!or[len-1]){
or.push(...or.splice(len-1,1))
}
len --
}
console.log(or) // [1, 3, 12, 0, 0]
function move (arr) {
let counter = 0
for (let index = 0; index < arr.length; index++) {
const item = arr[index];
if (item === 0) {
arr.splice(index, 1)
counter++
index--
}
}
arr.push(...new Array(counter).fill(0))
return arr
}
已修正连续多个 0 时的 bug
思路:用一个
len
记录 0 的出现次数,再过滤掉原数组中所有的 0,最后在数组末尾补上被移除的 0let arr = [1,2,3,0,7,0]
j = arr.length
for (i = 0; i < j; i++) {
if (arr[i] === 0) {
arr.splice(i,1)
arr.push(0)
}
}
let nums = [0,1,0,3,12];
新增:解决了有连续的0无法实现功能的问题。