题目描述
给定一个整数数组 nums 和一个值 val,要求原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。新数组的前 k 个元素为不等于 val 的元素,顺序可以任意,后续元素不影响评测。
算法思路
双指针法(头尾指针):通过左右指针从两端向中间遍历,高效处理元素替换。
具体步骤
-
初始化指针:
left:从数组起始位置开始,寻找等于val的元素。right:从数组末尾开始,提供可替换的非val元素。
-
循环处理:
- 当
nums[left] == val时,将nums[right]的值赋给nums[left],并将right左移。此时不移动left,因为新值可能仍等于val。 - 若
nums[left] != val,则left右移,继续检查下一个元素。 - 终止条件:当
left超过right时,所有有效元素已处理完毕。
- 当
-
结果返回:
left的值即为新数组的长度,其左侧均为有效元素。
过程示例
以 nums = [0,1,2,2,3,0,4,2],val = 2 为例:
| 步骤 | left | right | 操作 | nums 状态 |
|---|---|---|---|---|
| 初始 | 0 | 7 | - | [0,1,2,2,3,0,4,2] |
| 1 | 2 | 7 | 替换 nums[2] → nums[7]=2 | [0,1,2,2,3,0,4,2](right→6) |
| 2 | 2 | 6 | 替换 nums[2] → nums[6]=4 | [0,1,4,2,3,0,4,2](right→5) |
| 3 | 3 | 5 | 替换 nums[3] → nums[5]=0 | [0,1,4,0,3,0,4,2](right→4) |
| 终止 | 5 | 4 | left > 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
}
关键点总结
- 逆向覆盖:通过将尾部元素覆盖到需要删除的位置,避免数据搬移的开销。
- 双指针终止条件:当
left超过right时,所有有效元素已集中在数组前端。 - 元素检查:覆盖后需重新检查当前位置,确保替换后的值不等于
val。