哈希表:
C++ set与map、unordered_map、unordered_set与哈希表
c++ 创建哈希字典 unordered_map<int, int> mp // {key, value} 插值 mp[numbers[i]] = i;
创建哈希集合 unordered_set<ListNode *> visited; // 插值 visited.insert(headA);
python 创建哈希字典 d = {} // 插值 d[0] = 1
创建哈希集合 seen = set() // 插值 seen.add(head)
c++
unordered_map和map类似,都是存储的 key-value 的值,可以通过 key 快速索引到 value。不同的是 unordered_map 不会根据 key 的大小进行排序,存储时是根据 key 的 hash 值判断元素是否相同,即 unordered_map 内部元素是无序的,而 map 中的元素是按照二叉搜索树存储,进行中序遍历会得到有序遍历。
unordered_map 可类比于 Python 中的字典。其实现使用了哈希表,可以以 O(1) 的时间复杂度访问到对应元素,但缺点是有较高的额外空间复杂度。与之对应, STL 中的 map 对应的数据结构是红黑树,红黑树内的数据时有序的,在红黑树上查找的时间复杂度是 O(logN),相对于 unordered_map 的查询速度有所下降,但额外空间开销减小。
结论:如果需要内部元素自动排序,使用 map,不需要排序使用 unordered_map
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
unordered_map<int, int> mp; // 创建无序哈希表并重命名为mp,{key,value}={nums[i],i}
int temp;
for(int i = 0; i<numbers.size(); i++){
temp = target - numbers[i]; // 要找的数
if(mp.count(temp)){
return {mp[temp], i+1}; // 返回两个下标,且一定是匹配到一对中大的那个,(此时小的已经在表中,才匹配到。如果匹配一对中小的那个, 大的还有没有进表,无法成对(nums小到大排序))
}else{
mp[numbers[i]] = i+1;
}
}
return {-1, -1}; // 找不到
}
};
python
哈希表存 numbers[ i ], 找 target - numbers[ i ] 在不在表中,找到的一定是一对中大的那个,(小的已经被存入表中,大的才能匹配到小的)
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
d = {}
for i in range(len(numbers)):
temp = target - numbers[i]
if temp in d.keys():
return [d[temp], i+1] # python 字典返回不用{},用[]
else:
d[numbers[i]] = i+1
return [-1, -1]
enumerate 迭代器
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
d = {}
for index, num in enumerate(numbers):
temp = target - num
if temp in d:
return [d[temp], index+1]
else:
d[num] = index + 1
return [-1, -1]
双指针:
c++
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int left = 0, right = numbers.size()-1; // 双指针
int sum;
while(left < right){
sum = numbers[left] + numbers[right];
if (sum == target){
return {left+1, right+1}; // c++ 返回列表用 {}
}else if(sum < target){
left++; // right从最大的数开始遍历的,此时说明right右边的数已经不符合
}else{
right--; // sum大,sum要缩小, left 已经遍历过小的, right左移
}
}
return {-1, -1};
}
};
python
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
left, right = 0, len(numbers)-1
while left < right:
sum = numbers[left] + numbers[right]
if sum == target:
return [left+1, right+1]
elif sum < target: # sum 应该增大,right右边的已经遍历过,寻找left右边的
left += 1
else: # sum 应该减小,left左边的已经遍历过,寻找right左边的
right -= 1
return [-1, -1]