哈希表理论基础
哈希表是根据关键码的值而直接进行访问的数据结构。
![](https://img-blog.csdnimg.cn/direct/6991cfb5b1c043aca0e57fe1b69b6ac2.png)
- 数组
- set (集合)
- map(映射)
![](https://img-blog.csdnimg.cn/direct/0f070cc470b342ac861cb2472fccaccf.png)
![](https://img-blog.csdnimg.cn/direct/41b03aded0d443ca9bb8914634c33ccc.png)
- 当要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的;如果需要集合是有序的,那么就用set;如果要求不仅有序还要有重复数据的话,那么就用multiset。
总体来说,哈希表牺牲空间换取了时间,因为需要额外的数组来储存元素。
242.有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
class Solution {
public:
bool isAnagram(string s, string t) {
vector<int> hash1(26);
for(char c:s){
hash1[c-'a']++;
}
for(char c:t){ //只用一个hash表,可以省空间
hash1[c-'a']--;
}
for(int i=0; i<26; i++){
if(hash1[i]!=0){
return false;
}
}
return true;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
相关题目:
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
for(auto x:strs){
string word = x;
sort(word.begin(), word.end()); //用sort来 去重
mp[word].push_back(x);
}
vector<vector<string>> res;
for(auto x:mp){
res.push_back(x.second);
}
return res;
}
};
349. 两个数组的交集
给定两个数组,编写一个函数来计算它们的交集。
考虑使用unordered_set。
输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> s1; //做映射的时候效率最高
//不用构建第二个set,考虑给result构建一个set
unordered_set<int> res;
for(int i:nums1){
s1.insert(i);
}
for(int i:nums2){
if(s1.find(i)!=s1.end()){
res.insert(i); //用set储存,实现去重
}
}
return vector<int>(res.begin(), res.end());//将set转化为vector的方法
}
};
202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!
思考:计算一个数的每个位置的平方和记为sum,将sum储存在set中,进行循环,如果出现sum已经存在在set中了,则立马返回false,因为这个时候数字开始循环。
class Solution {
public:
int getsum(int n){ //获得每个数对应的平方和数
int sum = 0;
while(n){
sum+=(n%10)*(n%10);
n/=10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> st;
while(1){ //这是一个无限循环,将运行到明确发出中断语句为止
int sum = getsum(n);
if(sum == 1){
return true;
}
if(st.find(sum)!=st.end()){
return false;
}else{
st.insert(sum);
}
n = sum;
}
}
};
while(1) 是一个无限循环,将运行到明确发出中断语句为止。
while(0)则相反,It means condition will always be false and thus code in while will never get executed. 代码并不会运行
1. 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
暴力的解法是两层for循环查找,时间复杂度是O(n^2)。
本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
unordered_map是哈希表,而map和multimap是红黑树。这道题不需要考虑有序的key,所以最好选取unordered_map。
- map用来做什么
- map中key和value分别表示什么
需要注意的点:
- 如何在map中遍历?
unordered_map<int, int>::iterator iter;
iter = mp.find(i); for(iter!=mp.end()){ return {iter->second, i}; }
- map insert()的用法
mp.insert(pair<int, int>(nums[i], i));
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> mp;
unordered_map<int, int>::iterator iter;
for(int i=0; i<nums.size(); i++){
int s = target-nums[i];
iter = mp.find(s);
if(iter!=mp.end()){
return {iter->second, i};
}else{
mp.insert(pair<int, int>(nums[i], i));
}
}
return {};
}
};