27. 移除元素

双指针 1

使用快慢指针,保持原有的元素顺序

慢指针指向当前准备赋值的位置,快指针去遍历所有的元素

function removeElement(nums: number[], val: number): number {
  let slow = 0 // 指向当前准备赋值的位置
  let fast = 0 // 指向当前检查的位置

  while (fast < nums.length) {
    // 当不等于 val 的时候可以对 slow 进行赋值
    if (nums[fast] !== val) {
      nums[slow] = nums[fast]

      slow += 1 // 向后移动一位,同时也是当前状态下的 len
    }

    // 检查下一个
    fast += 1
  }

  return slow
}

双指针 2

使用对撞指针,不保持原有的元素顺序,性能优于双指针 1

left 和 slow 用处一样,但是 right 指针从末尾往前面遍历,相遇的时候即处理完了

function removeElement(nums: number[], val: number): number {
  // 指向当前准备检查的位置
  // 因为检查通过后会 +1 再次检查下一位
  // 所以每一轮结束的时候 left 就是当前状态下的 len
  let left = 0
  let right = nums.length - 1 // 指向当前检查的位置

  // left <= right 的时候需要处理
  // 因为 right 从 nums.length - 1 开始处理
  // 所以需要处理完当前位置的 right
  // 如果从 nums.length 开始处理的话,那么使用 left < right 即可
  // 不过这种情况下赋值的时候应该赋值 right - 1 的值
  while (left <= right) {
    // 如果 left === val
    // 使用 right 替代,然后再次判断是否满足条件
    if (nums[left] === val) {
      nums[left] = nums[right]

      right -= 1 // 向前移动一位,接着判断 left
    } else {
      // left !== val
      // 检查下一个
      left += 1
    }
  }

  return left
}

双指针 3

使用对撞指针

和双指针 2 的区别是