算法题:将数组中的0移动到末尾

题目

  • 如输入 [1, 0, 3, 0, 11, 0],输出 [1, 3, 11, 0, 0, 0]
  • 只移动0,其他顺序不变
  • 必须在原数组进行操作

传统思路

  • 遍历数组,遇到0则push到数组末尾
  • 用 splice 截取掉当前元素
  • 时间复杂度 O(n^2) ——算法不可用

优化思路 - 双指针

  • 定义一个变量zeroIndex,用来记录第一个0的位置
  • 遍历数组,zeroIndex找到第一个0,i找到zeroIndex后面第一个非0
  • 交换位置,继续向后移动
  • 之遍历一次,所以时间复杂度是O(n)
/**
 * @description 移动 0 到数组末尾
 * @author lsr
 */

/**
 * 移动 0 到数组末尾 - 嵌套循环
 * @param arr
 * @returns
 */
export function moveZero1(arr: number[]) {
  let length = arr.length
  if (length === 0) return

  for (let i = 0; i < length; i++) {
    if (arr[i] === 0) {
      arr.push(0)
      arr.splice(i, 1)
      // 排除末尾0的循环,否则会进入死循环
      length--
      // 截取之后,i--,重新判断当前值是否非0
      i--
    }
  }
}

/**
 * 移动 0 到数组末尾 - 双指针
 * @param arr
 * @returns
 */
export function moveZero2(arr: number[]) {
  const length = arr.length
  if (length === 0) return

  let zeroIndex = -1 // 0的索引
  for (let i = 0; i < length; i++) {
    // 找到第一个0
    if (arr[i] === 0 && zeroIndex < 0) {
      zeroIndex = i
    }

    // 找到第一个非0
    if (arr[i] !== 0 && zeroIndex >= 0) {
      // 与0交换位置
      const n = arr[i]
      arr[i] = arr[zeroIndex]
      arr[zeroIndex] = n
      
      // 指向下一个0
      zeroIndex++
    }
  }
}

// 功能测试
// const arr1 = [1, 0, 3, 0, 11, 0]
// moveZero1(arr1)
// console.log(arr1)
// const arr2 = [1, 0, 3, 0, 11, 0]
// moveZero1(arr2)
// console.log(arr2)

// 性能测试
const arr1 = []
for (let i = 0; i < 20 * 10000; i++) {
  if (i % 10 === 0) {
    arr1[i] = 0
  } else {
    arr1[i] = i
  }
}
console.time('moveZero1')
moveZero1(arr1)
console.timeEnd('moveZero1') // 178.4111328125 ms

const arr2 = []
for (let i = 0; i < 20 * 10000; i++) {
  if (i % 10 === 0) {
    arr2[i] = 0
  } else {
    arr2[i] = i
  }
}
console.time('moveZero2')
moveZero2(arr2)
console.timeEnd('moveZero2') // 1.7041015625 ms

单元测试

/**
 * @description 移动 0 到数组末尾 test
 * @author lsr
 */

import { moveZero1, moveZero2 } from '@/01-algorithm/move-zero'

describe('移动 0 到数组末尾', () => {
  it('正常情况', () => {
    const arr = [1, 0, 3, 0, 11, 0]
    moveZero2(arr)
    expect(arr).toEqual([1, 3, 11, 0, 0, 0])
  })
  it('没有0', () => {
    const arr = [1, 1, 1, 1, 1, 1]
    moveZero2(arr)
    expect(arr).toEqual([1, 1, 1, 1, 1, 1])
  })
  it('全是0', () => {
    const arr = [0, 0, 0, 0, 0, 0]
    moveZero2(arr)
    expect(arr).toEqual([0, 0, 0, 0, 0, 0])
  })
})

划重点

  • 审题:是否必须修改原数组
  • 数组是连续存储,慎用splice、unshift 等API
  • 双指针思路
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值