一、哈希表理论基础,代码随想录
1.1 常见的三种哈希结构
1)数组、2)set (集合)、3)map(映射)
1.2 在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:
std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。
std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。
1.2.1 使用选择
1)集合
当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。
2)映射
那么再来看一下map ,在map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树实现的。
二、有效的字母异位词,力扣题目链接
2.1 题目的第一想法
不难
1)用哈希法
class Solution {
public:
bool isAnagram(string s, string t) {
if(s.size()!=t.size()) //开始没想到判断长度
return false;
unordered_map m1,m2; //map的key是有序的
for(int i=0;i
2)用排序+遍历
class Solution {
public:
bool isAnagram(string s, string t) {
if(s.size()!=t.size())
return false;
sort(s.begin(),s.end());
sort(t.begin(),t.end());
for(int i=0;i
2.1)力扣官方,最后不用遍历,直接用==
class Solution {
public:
bool isAnagram(string s, string t) {
if(s.size()!=t.size())
return false;
sort(s.begin(),s.end());
sort(t.begin(),t.end());
return s==t; //直接判断两个字符串是否相等
}
};
2.2 看完代码随想录之后的想法,代码随想录
三、两个数组的交集,力扣题目链接
3.1 题目的第一想法
1)set+两次遍历、再set转vector
class Solution {
public:
vector intersection(vector& nums1, vector& nums2) {
vector ans;
unordered_set s1,s2;
for(int i=0;i
2)map+两次遍历
class Solution {
public:
vector intersection(vector& nums1, vector& nums2) {
vector ans;
unordered_map m1,m2;
for(int i=0;i
3)改进 set,不需要set转vector
class Solution {
public:
vector intersection(vector& nums1, vector& nums2) {
vector ans;
unordered_set s1,s2;
for(int i=0;i
3.2 看完代码随想录之后的想法,代码随想录
class Solution {
public:
vector intersection(vector& nums1, vector& nums2) {
unordered_set result_set; // 存放结果,之所以用set是为了给结果集去重
unordered_set nums_set(nums1.begin(), nums1.end());
for (int num : nums2) {
// 发现nums2的元素 在nums_set里又出现过
if (nums_set.find(num) != nums_set.end()) {
result_set.insert(num);
}
}
return vector(result_set.begin(), result_set.end());
}
};
跟自己的set思路一致,只是用迭代器一步直接将vector转set,结束再set转vector,记住这种方法。
四、快乐数,力扣题目链接
4.1 题目的第一想法
开始没想到循环结束的条件,看到任务中有提示用set就明白了
class Solution {
public:
bool isHappy(int n) {
string s=to_string(n);
vector v(s.begin(),s.end());
int sum=0;
for(int i=0;i s1;
while(s1.count(sum)==0 && sum!=1)
{
s1.insert(sum);
s=to_string(sum);
sum=0;
vector v1(s.begin(),s.end());
for(int i=0;i
4.2 看完代码随想录之后的想法,代码随想录
自己求和写得过于复杂了,按着答案重写了一下自己的
class Solution {
public:
bool isHappy(int n) {
int sum=0;
while(n)
{
sum+=(n%10)*(n%10);
n/=10;
}
unordered_set s1;
while(s1.count(sum)==0 && sum!=1)
{
s1.insert(sum);
n=sum;
sum=0;
while(n)
{
sum+=(n%10)*(n%10);
n/=10;
}
}
return sum==1;
}
};
五、两数之和,力扣题目链接
5.1 题目的第一想法
class Solution {
public:
vector twoSum(vector& nums, int target) {
vector ans;
unordered_map map;
for(int i=0;isecond);
break;
}
}
return ans;
}
};
结果:
5.2 看完代码随想录之后的想法,代码随想录
1)关键点是,使用find函数,判断元素是否出现,这个元素就要作为key ;
2)自己是先建立哈希map,再遍历,不是遍历中没有匹配再加入map中;感觉没有匹配再加入map,这样空间复杂度更低,且可以解决两个相同数字的问题。
class Solution {
public:
vector twoSum(vector& nums, int target) {
std::unordered_map map;
for(int i = 0; i < nums.size(); i++) {
// 遍历当前元素,并在map中寻找是否有匹配的key
auto iter = map.find(target - nums[i]);
if(iter != map.end()) {
return {iter->second, i};
}
// 如果没找到匹配对,就把访问过的元素和下标加入到map中
map.insert(pair(nums[i], i));
}
return {};
}
};