哈希表理论基础
- 什么时候用哈希表:当我们遇到要快速判断一个元素是否出现再集合里的时候,就要考虑哈希法。
- 哈希法的缺点:牺牲了空间换时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
- 哈希碰撞的解决办法:拉链法和线性探测法。
- 常见的哈希结构:数组,set(集合)、map(映射)
- 简单来说,在数据量较小,范围可控的情况下就用数组就行了;数据量较大的话用set;每一个k对应一个value的话就用map。
- 当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。
- 看文章set跟map的描述
LeetCode242 有效的字母异位词
由于是第一次写有关哈希表的题目,所以还不熟悉怎么做,全程都是跟着视频的思路去写的。
在这道题中,因为传进来的只有小写字母,且字母一共才26位,我们只需要判断两个字符串的哈希表是否一样就可以了,代码中的s[i] - 'a’其实就是哈希函数了。它将每一个字母转化为一个对应的索引。
正确代码:
class Solution {
public:
bool isAnagram(string s, string t)
{
int hash[26] = {0};
for (char i: s)
{
hash[i - 'a']++;
}
for (char i: t)
{
hash[i - 'a']--;
}
for (int i: hash)
{
if (i)
{
return false;
}
}
return true;
}
};
LeetCode349 两个数组的交集
上题是第一次用哈希,这道题就是第一次用set= =。
其实就是,看回基础理论的第一点,我们所要做的,也就是将第一个数组变成哈希表,然后在第二个数组里面去查哈希表是否存在这个元素,如果纯在就输出,注意去重。所以当我们要快速判断一个元素是否出现再集合里的时候,记得用哈希表去做,这样会快速不少。
这道题有两种做法,一种是用set,另一种则是用数组,对于一千来说,数组的空间复杂度与时间复杂度都要比set更快。
先看set的:
class Solution {
public:
vector<int> intersection(vector<int> &nums1, vector<int> &nums2)
{
unordered_set<int> res;
unordered_set<int> num(nums1.begin(), nums1.end());
for (int i: nums2)
{
if(num.find(i)!=num.end())
{
res.insert(i);
}
}
return vector<int>(res.begin(),res.end());
}
};
再看数组的:
class Solution {
public:
vector<int> intersection(vector<int> &nums1, vector<int> &nums2)
{
unordered_set<int> res;
int hash[1001] = {0};
for(int i:nums1)
{
hash[i]++;
}
for(int i:nums2)
{
if(hash[i])
{
res.insert(i);
}
}
return vector(res.begin(),res.end());
}
};
LeetCode202 快乐数
这道题看着像是一道数学问题,但是实际上是一道哈希表的题目。这个要求我们要去审题,发现题目中所提示我们的。就像这题一样,已经告诉我们是无限循环的,这样子就会出现重复出现的,运用哈希表就可以快速匹配看是否有重复的。但这道题不能用数组去做,因为我们是无法知道给的数字为多大,这会让我们不知道开多大的数组空间。
正确代码:
class Solution {
public:
bool isHappy(int n)
{
unordered_set<int> Count;
do
{
int sum = 0;
while (n)
{
int Tem = n % 10;
sum += Tem * Tem;
n /= 10;
}
if (Count.find(sum) == Count.end())
{
Count.insert(sum);
}
else
{
return false;
}
n = sum;
} while (n != 1);
return true;
}
};
LeetCode1 两数之和
这道题是有关map的使用。最多的是了解map的使用方法。
正确代码:
class Solution {
public:
vector<int> twoSum(vector<int> &nums, int target)
{
unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++)
{
auto iter = map.find(target - nums[i]);
if (iter != map.end())
{
return {iter->second, i};
}
else
{
map.insert({nums[i], i});
}
}
return {};
}
};