在LeetCode做简单数组题的第4天
一、题目描述
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素。元素的顺序可以改变。然后返回 nums 中不等于 val 的元素数量。
要求:
- 在原数组上修改,不能新开数组
- 数组前 k 位保存所有不等于 val 的元素
- 返回 k,后面的元素不管
- 评测逻辑:只检查前 k 个元素是否符合预期
示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,,]
解释:你的函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3,,,_]
解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
二、我的简单思路
开辟一个存下标空位的空数组,然后对题目数组进行遍历,用if判断当前空间存储的值是否为val,若是,则加入空位池,若不是,则再用if判断一下空位是否有空位,若有,则把当前空间的值存入第一个空位,然后删除该空位,并存入当前空间的下标,若没有,则不做修改。
循环结束后,空位池内只剩下与val总数相同的下标数量。
我用两个if判断句,保证了前k个值一定是原数组删去val后的那k个值后的原顺序序列。
class Solution:
def removeElement(self, nums: list[int], val: int) -> int:
removeIndex = []
for i in range(len(nums)):
if nums[i] == val:
# 是要删除的值,直接记录空位
removeIndex.append(i)
else:
if removeIndex:
# 取出一个空位,把当前元素填过去
j = removeIndex.pop(0)
nums[j] = nums[i]
# 原来i的位置空出来了,加入空位池
removeIndex.append(i)
# 最终保留的数量 = 总长度 - 空位总数
k = len(nums) - len(removeIndex)
return k
👉 漏洞:
没理解题目不需要真正删除元素,只需要覆盖,保证前k个有效就行
这道题核心不是“删除”,是原地覆盖。
缺点:需要额外开列表存下标,空间不是 O(1)。
时间复杂度:O(n^2)
如果简单把
list.pop(0)看作是 O (n) 操作的话。Python 的列表是动态数组,不是链表。pop(0)删掉第一个元素之后,后面所有元素全部要往前挪一位。
三、最优解——快慢指针
快指针找合格的数,慢指针负责守位置,找到合格的就搬到慢指针位置。
def removeElement(nums, val):
slow = 0
for fast in range(len(nums)):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
return slow
- 慢指针 slow:指向下一个有效元素要放的位置
- 快指针 fast:向前遍历,寻找不等于 val 的有效元素
- 快找到有效元素,就放到慢指针位置,慢指针 + 1
测试样例
样例1
nums = [3,2,2,3], val = 3
输出:k=2,nums前2位 [2,2]
样例2
nums = [0,1,2,2,3,0,4,2], val = 2
输出:k=5,nums前5位 [0,1,3,0,4]
四、对比两种方案
| 方案 | 空间复杂度 | 时间复杂度 |
|---|---|---|
| 收集下标 | O(n) | O(n^2) |
| 快慢指针 | O(1) | O(n) |
五、总结
对于原地数组题,优先考虑双指针,尽量不要新开数组。
浙公网安备 33010602011771号