哈希表教程:代码随想录
242. 有效的字母异位词:力扣
349. 两个数组的交集:力扣
第202题. 快乐数:
1. 两数之和:力扣
哈希表
根据关键码的值而直接进行访问的数据结构。
牺牲空间换时间。
哈希碰撞
- 拉链法:需要选择合适的哈希表大小,避免哈希表过空,也避免拉链过长
- 线性探测法:确保哈希表大小大于数据总数
哈希表实现
- 数组
- set
- map
C++ Set / Map
底层实现 | 查询效率 | 增删效率 | 有序 | 是否重复 | |
---|---|---|---|---|---|
std::set std::map | 红黑树 | O(logn) | O(logn) | 有序 | 不可重复 |
std::multi_set std::multi_map | 红黑树 | O(logn) | O(logn) | 有序 | 可重复 |
std::unordered_set std::unordered_map | 哈希表 | O(1) | O(1) | 无序 | 不可重复 |
- 红黑树是一种平衡二叉搜索树,key值有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。
C++求交并:std::set_intersection, std::set_union
std::set_intersection 和 std::set_union要求容器内部有序!
因此不能直接应用于unordered_set
vector<int> intersect_vector(vector<int> a, vector<int> b)
{
sort(a.begin(), a.end());
sort(b.begin(), b.end());
vector<int> res;
res.reserve(a.size() + b.size());
set_intersection(a.begin(), a.end(), b.begin() , b.end(), back_insert_iterator<vector<int>>(res));
return res;
}
back_insert_iterator: push_back迭代器
std::vector<int> v;
std::back_insert_iterator<std::vector<int>> it(v);
*it = 10; // it is equivalent to v.push_back(10);
it = 99; // it is ALSO equivalent to v.push_back(99);
for (auto const & i : v)
std::cout << i << " " ; //10 99
Leetcode 242. 有效的字母异位词
给定两个字符串 s
和 t
,编写一个函数来判断 t
是否是 s
的字母异位词。
注意:若 s
和 t
中每个字符出现的次数都相同,则称 s
和 t
互为字母异位词。
bool isAnagram(string s, string t) {
int hash[26];
memset(hash, 0, sizeof(int) * 26);
for(auto i: s){
hash[i - 'a'] += 1;
}
for(auto i: t){
hash[i - 'a'] -= 1;
}
for(int i = 0; i < 26; i++){
if(hash[i] != 0) return false;
}
return true;
}
349. 两个数组的交集
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
解法:
- 考虑vector实现的哈希表,复杂度O(n)
- 考虑集合操作,最常使用的unordered_set,但是C++中没有直接定义的对集合求交的函数,自行实现的话仍然需要O(n)复杂度
- 考虑set,构造和查询都要O(logn),总体需要O(nlogn)复杂度
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<bool> hash(1001), set_union(1001);
vector<int> res;
for(auto i: nums1) hash[i] = true;
for(auto i: nums2){
if(hash[i]) set_union[i] = true;
}
for(int i = 0; i <= 1000; i++){
if (set_union[i] != 0) res.push_back(i);
}
return res;
}
};
第202题. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
class Solution {
public:
int cal_square(int x){
int res = 0;
while(x){
int temp = x % 10;
res += temp * temp;
x /= 10;
}
return res;
}
bool isHappy(int n) {
unordered_set<int> st;
st.insert(n);
while(n != 1){
n = cal_square(n);
if(st.count(n)) return false;
st.insert(n);
}
return true;
}
};
1. 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> index;
for(int i = 0; i < nums.size(); i++){
if(index.count(target - nums[i])) return vector<int>{i, index[target - nums[i]]};
index[nums[i]] = i;
}
return vector<int>{-1, -1};
}
};