美文网首页
TS数据结构与算法之移动0到数组的末尾

TS数据结构与算法之移动0到数组的末尾

作者: 子十一刻 | 来源:发表于2022-03-13 19:19 被阅读0次

问题

  • 将数组中的0移动到末尾
  • 如输入 [1, 0, 3, 0, 11, 0], 输出 [1, 3, 11, 0, 0, 0]
  • 只移动0, 其它顺序不变
  • 必须在原数组进行操作

方案1:如果不限制“必须在原数组操作”

  • 定义 part1, part2 两个数组
  • 遍历数组,非0 push到 part1, 0 push 到 part2
  • 最后返回 part1.concat(part2)

此方案非常简单,但不符合第3限制条件

方案2:传统思路

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

代码演示

/**
 * 移动 0 到数组和末尾(嵌套循环)
 */
export const moveZero1 = (arr: number[]): void => {
  const len = arr.length;
  if (!len) return;

  let zeroLength = 0;
  // 整体 O(n^2)
  for (let i = 0; i < len - zeroLength; i++) {
    if (arr[i] === 0) {
      arr.push(0);
      // 本身就有 O(n)
      arr.splice(i, 1);
      // [1, 0, 0, 0, 1, 0]
      // 数组截取了一个元素, i 要递减,否则连续 0 就会有错误
      i --;
      zeroLength ++; // 累加 0 的长度
    }
  }
}

方案3 - 优化使用双指针

  • 定义 j 指向第一个 0,i 指向 j 后面的第一个非 0
  • 交换 i 和 j 的值,继续向后移动
  • 只遍历一次,所以时间复杂度是 O(n)
[1, 0, 0, 1, 1, 0]
    j     i

交换:

[1, 1, 0, 0, 1, 0]
       j     i

再交换

[1, 1, 1, 0, 0, 0]

代码演示

/**
 * 移动 0 到数组和末尾(双指针)
 */
export const moveZero2 = (arr: number[]): void => {
  const len = arr.length;
  if (!len) return;

  let i;
  let j = -1; // 指向第一个0

  for (i = 0; i < len; i++) {
    if (arr[i] === 0) {
      // 第一个0
      if (j < 0) {
        j = i;
      }
    }

    // i 指向第一个非0 j指向第一个0时
    if (arr[i] !== 0 && j >= 0) {
      // 交换
      const n = arr[i];
      arr[i] = arr[j];
      arr[j] = n;

      // j 向后移动
      j++;
    }
  }
};

功能测试

export const moveZeroFunctionalTest = () => {
  const arr = [1, 0, 3, 4, 0, 0, 11, 0];
  moveZero2(arr);
  console.log(arr); // [1, 3, 4, 11, 0, 0, 0, 0]
};

单元测试

/**
 * @description 将0移动到数组末尾单元测试
 */
import { moveZero2 } from '../src/utils/move-zero';
describe('移动0到数组末尾', () => {
  test('正常情况', () => {
    const arr = [1, 0, 3, 4, 0, 0, 0, 11, 0];
    moveZero2(arr);
    expect(arr).toEqual([1, 3, 4, 11, 0, 0, 0, 0, 0]);
  });

  test('没有0', () => {
    const arr = [1, 3, 4, 11];
    moveZero2(arr);
    expect(arr).toEqual([1, 3, 4, 11]);
  });

  test('全是0', () => {
    const arr = [0, 0, 0, 0, 0];
    moveZero2(arr);
    expect(arr).toEqual([0, 0, 0, 0, 0]);
  });
});

运行 yarn jest:

PASS  tests/move-zero.test.ts
  移动0到数组末尾
    √ 正常情况 (1 ms)
    √ 没有0
    √ 全是0

性能测试

分别使用两种方案操作有20W条数据的数组

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

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

输出:

  • moveZero1: 2006.822998046875 ms
  • moveZero2: 1.85302734375 ms

重点

  • 首先先确认: 是否必须修改原数组?
  • 数组是连续存储,要慎用 splice unshift 等 API
  • 双指针思路

相关文章

  • TS数据结构与算法之移动0到数组的末尾

    问题 将数组中的0移动到末尾 如输入 [1, 0, 3, 0, 11, 0], 输出 [1, 3, 11, 0, ...

  • 重温:数据结构与算法 - 03数组

    数据结构与算法之美 - 数组 数据结构与算法之美-学习大纲 什么数组? 数组是一种 线性表 数据结构。它用一组 连...

  • 数据结构与算法之美(二):数组

    本章内容源于笔者对极客时间《数据结构与算法之美》以下章节的学习笔记: 数组:为什么很多编程语言中数组都从0开始编号...

  • 数据结构与算法

    数据结构与算法之美 数据结构与算法之美1--如何学数据结构与算法之美2--复杂度分析(上)数据结构与算法之美3--...

  • Hash算法

    数据结构与算法分析:大纲数据结构:数组算法:hash算法算法:排序算法Java实现 1 Hash算法? 将任意长度...

  • leetcode算法题学习Java版(2)

    283.Move Zeros(移动零) 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持...

  • leetcode 初级之数组篇 08

    283. Move Zeroes 移动零给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持...

  • LeetCode热门100题算法和思路(day8)

    LeetCode283 移动零 题目详情 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保...

  • LeetCode-python 283.移动零

    题目链接难度:简单 类型: 数组 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾...

  • 数据结构:数组

    00数据结构与算法分析:大纲01数据结构:数组02数据结构:链表03数据结构:栈03数据结构:队列 数组 数组是一...

网友评论

      本文标题:TS数据结构与算法之移动0到数组的末尾

      本文链接:https://www.haomeiwen.com/subject/udkddrtx.html