leetcode 面试经典 150 题(2/150) 27.移除元素

101 阅读2分钟

题目描述

给定一个整数数组 nums 和一个值 val,要求原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。新数组的前 k 个元素为不等于 val 的元素,顺序可以任意,后续元素不影响评测。

算法思路

双指针法(头尾指针):通过左右指针从两端向中间遍历,高效处理元素替换。

具体步骤

  1. 初始化指针

    • left:从数组起始位置开始,寻找等于 val 的元素。
    • right:从数组末尾开始,提供可替换的非 val 元素。
  2. 循环处理

    • nums[left] == val 时,将 nums[right] 的值赋给 nums[left],并将 right 左移。此时不移动 left,因为新值可能仍等于 val
    • nums[left] != val,则 left 右移,继续检查下一个元素。
    • 终止条件:当 left 超过 right 时,所有有效元素已处理完毕。
  3. 结果返回

    • left 的值即为新数组的长度,其左侧均为有效元素。

过程示例

nums = [0,1,2,2,3,0,4,2]val = 2 为例:

步骤leftright操作nums 状态
初始07-[0,1,2,2,3,0,4,2]
127替换 nums[2] → nums[7]=2[0,1,2,2,3,0,4,2](right→6)
226替换 nums[2] → nums[6]=4[0,1,4,2,3,0,4,2](right→5)
335替换 nums[3] → nums[5]=0[0,1,4,0,3,0,4,2](right→4)
终止54left > right → 返回 5有效元素为前5个:[0,1,4,0,3]

复杂度分析

  • 时间复杂度:O(n),每个元素至多被访问一次。
  • 空间复杂度:O(1),原地修改数组,未使用额外空间。

代码实现

func removeElement(nums []int, val int) int {
    left := 0
    right := len(nums) - 1
    for left <= right {
        if nums[left] == val {
            nums[left] = nums[right]
            right--
        } else {
            left++
        }
    }
    return left
}

关键点总结

  1. 逆向覆盖:通过将尾部元素覆盖到需要删除的位置,避免数据搬移的开销。
  2. 双指针终止条件:当 left 超过 right 时,所有有效元素已集中在数组前端。
  3. 元素检查:覆盖后需重新检查当前位置,确保替换后的值不等于 val