【LeetCode】4. 去重的效率提升
看一道简单题
初始做法
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
hashMap = []
k = 0
for i in nums:
if i not in hashMap:
hashMap.append(i)
nums[k] = i
k += 1
nums[:] = nums[:k]
return k
这个做法建立了一个数组用来存储重复值。
if i not in hashMap
会导致多次遍历,猜测是这一段增加了内存消耗。
优化思路应该将遍历减少到最低
使用set优化
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
seen = set() # 用于记录已出现的元素
k = 0 # 指向放置下一个唯一值的位置
for i in nums:
if i not in seen:
seen.add(i) # 将新元素添加到集合中
nums[k] = i # 将唯一值放到 nums 的前面
k += 1
# 保留前 k 个元素
nums[:] = nums[:k]
return k
注意set是基于 哈希表 实现的
set 比 list 效率高,尤其是在执行查找操作时,这是因为两者底层的实现机制不同。具体原因如下:
1. list 的实现
数据结构: list 是一种动态数组,元素按插入顺序连续存储。
查找操作:
当你执行 x in list,Python 必须从头开始遍历列表中的每个元素,逐一检查是否等于 x。
最坏情况下需要检查所有元素,时间复杂度为 O(n)。
适合的场景:
适用于需要保留元素顺序或频繁执行索引访问(list[i],时间复杂度为 O(1)。
2. set 的实现
数据结构:
set 是基于 哈希表 的无序集合。
每个元素会通过哈希函数映射到一个特定的存储位置(桶)。
哈希表通过哈希值快速定位元素的位置,而无需遍历整个集合。
查找操作:
当你执行 x in set,Python 使用哈希函数计算 x 的哈希值,然后直接定位到对应的存储桶,查看是否存在。
在没有大量哈希冲突的情况下,查找的时间复杂度为 O(1)。
即使发生哈希冲突(两个不同的值映射到相同的桶),通过链表或其他冲突处理机制,效率仍然远高于线性查找。
适合的场景:
适用于频繁执行查找、插入、删除操作,且不需要关心元素顺序。