第三专题 映射(Map)与集合(Set)
HashTable & Hash Function:
使用hash函数将key所对应的字符通过hash算法计算出value存放的地址,使用hash函数也总是不可避免的发生hash碰撞,当两个key通过hash算出的相同时,可以使用拉链法和红黑树解决该问题。
Map vs Set
HashMap,HashSet,平均时间复杂度为O(1) 特点:无序存储,快
TreeMap,TreeSet,平均时间复杂度为O(logN) 特点:有序存储
不同语言中常用的hashmap特性
编程语言 | 使用的hashmap 特性 |
---|---|
Python | 所对应的数据结构为dict, 默认为hashmap={key:value},如果想使用TreeMap需要引入其他第三方引入 |
Java | 需要具指定为HashMap或者TreeMap |
C++ | std::unordered_map std::map |
C# | Dictionary<Tkey,Tvalue> Hashtable;StringDictionary;SortedDictionary |
1. leetcode242. 有效的字母异位词
方法1:使用HashMap
分别遍历两个字符串,分别将两个字符串的中出现的字母和次数存入Hash表,比较两个HashMap的是否相等。
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
s_dict = dict()
for c in s:
if c not in s_dict:
s_dict[c] = 0
s_dict[c] += 1
t_dict = dict()
for c in t:
if c not in t_dict:
t_dict[c] = 0
t_dict[c] += 1
return s_dict == t_dict
方法2:使用列表构建HashMap
使用两个列表,由于默认都是小写字母,则可以预定义两个长度为26的列表,在遍历两个字符串时,比较每一个元素与’a’的ascii码之差作为列表索引,每次遍历向所对应的列表中的值增加1
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
lst_s,lst_t = [0]*26,[0]*26
for i in s:
lst_s[ord(i)-ord('a')] += 1
for c in t:
lst_t[ord(c)-ord('a')] += 1
return lst_s == lst_t
2. leetcode1. 两数之和
leetcode第一题,思路和方式比较固定了,使用hashmap能够相对于暴力求解的O(N^2)的时间复杂度优化到O(N)。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
dic = dict()
for ind, num in enumerate(nums):
if target - num in dic:
return [ind, dic[target-num]]
dic[num] = ind
return []
3. leetcode15. 三数之和
方法1 两层遍历,用set查找第第三值
使用两层循环求解两个元素之和,判断第三个元素元素是否等于两个元素之和取反,为了降低时间复杂度,可以使用set查找,将时间复杂度降为O(N^2)
简单版:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3:
return []
nums.sort()
res = []
for i,v in enumerate(nums[:-2]):
if i >= 1 and v == nums[i-1]:
continue
d = {}
for x in nums[i+1:]:
if x not in d:
d[-v-x] = 1
else:
if [v, -v-x, x] not in res:
res.append([v, -v-x, x])
return res
精炼版:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3: return []
nums.sort()
res = set()
for i,v in enumerate(nums[:-2]):
if i >= 1 and v == nums[i-1]:
continue
d = {}
for x in nums[i+1:]:
if x not in d:
d[-v-x] = 1
else:
res.add((v, -v-x, x))
return list(map(list, res))
方法2. 排序,双指针
先对数组进行排序sort, 快速排序时间复杂度为O(NlogN),然后遍历取出一个元素,然后使用双指针分别前面和后面遍历,寻找满足条件的值,时间复杂度为O(N2)。因此总的时间复杂度为O(N2).
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3:
return []
nums.sort()
res = []
for i,f1 in enumerate(nums[:-2]):
if i >= 1 and nums[i-1] == f1:
continue
l,r = i+1,len(nums)-1
while l < r:
if f1+nums[l]+nums[r] < 0:
l += 1
elif f1+nums[l]+nums[r] > 0:
r -= 1
else:
if [f1,nums[l],nums[r]] not in res:
res.append([f1,nums[l],nums[r]])
l += 1
r -= 1
return res