哈希表理论基础
哈希表
哈希函数hashcode()
哈希碰撞(哈希冲突)
解决哈希冲突方法:1.拉链法(链表存同哈希值元素)2.线性探测法(放到下一个位置)
三种常见哈希结构:数组、set、map
242.有效的字母异位词
class Solution242{
public:
/// @brief 给定两个字符串s和t判断t是否是s的字母异位词
/// 字符串中每个出现过的字符出现的次数都相同即为字母异位词
/// @param s
/// @param t
/// @return
bool isAnagram(string s,string t){
// 哈希表专题,就直接用哈希表了
unordered_map<char,int> res_map;
char *sPtr=&s[0];
char *tPtr=&t[0];
while(*sPtr!='\0'){
res_map[*sPtr]=0;
sPtr++;
}
while(*tPtr!='\0'){
res_map[*tPtr]=0;
tPtr++;
}
sPtr=&s[0];
tPtr=&t[0];
while(!(*sPtr=='\0'||*tPtr=='\0')){
res_map[*sPtr]++;
res_map[*tPtr]--;
sPtr++;
tPtr++;
if((*sPtr=='\0'&&*tPtr!='\0')||(*sPtr!='\0'&&tPtr=='\0')){
return false;
}
}
sPtr=&s[0];
tPtr=&t[0];
while(*sPtr!='\0'){
if(res_map[*sPtr]!=0){
return false;
}
sPtr++;
}
while(*tPtr!='\0'){
if(res_map[*tPtr]!=0){
return false;
}
tPtr++;
}
return true;
}
};
代码思路很简单,但是写的很长,写的时候脑子也不清醒,犯了好多低级的语法错误。
就是简单地初始化map里面每个char的值为0
然后对char索引来加减
最后判断是否全为0即可。
写的好长好丑。。
看到题解焕然大悟,,又去读了遍题,,s和t仅包含小写字母!!!!26长度的数组就能解决。。。初始化也不麻烦了。。要认真读题啊!!!
然后发现自己对这几个库运用不熟练,去看了看一些教程。。
349. 两个数组的交集
先读题(防止出现上一题的麻烦
两个数组的交集,不考虑顺序,输出结果每个元素唯一,ok可以不考虑数量,直接用undordered_set,把第一个的全部元素加进去,然后遍历2,把在集合中的添加到结果集合,最后返回结果集合即可
class Solution349{
public:
/// @brief 给定两个数组 返回交集
/// @param nums1
/// @param nums2
/// @return
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> numSet(nums1.begin(),nums1.end());
unordered_set<int> result;
for(int i=0;i<nums2.size();i++){
if(numSet.find(nums2[i])!=numSet.end()){
result.insert(nums2[i]);
}
}
vector<int> resultVec(result.begin(),result.end());
return resultVec;
}
};
比较简单,然后看了看文章,思路也差不多。
其实我看到nums的数值范围之后也想直接用数组来的。。。
202.快乐数
定义:
1.对于正整数 每次将其替换为每个位置上的数字平方和。
2.重复这个过程直到这个数变为1,也可能永远变不成1
3.如果变为1则为快乐数
没思路。。。思考这个过程和哈希的共同点?
想变成1,上一步就得到10的幂,
1和3 10,6和8 100,,没了
然后。。10个和10个3,10个6和10个8.。好像已经想偏了
看文章了,,看到无限循环这几个字,,重复出现,嗯懂了。
就循环计算,每次计算记录结果,如果结果已经在哈希表中出现过一次,那么就false,,如果得到1就true。ok,编码
class Solution202{
public:
/// @brief 编写一个算法来判断一个数 n 是不是快乐数。
/// 「快乐数」 定义为:
/// 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
/// 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
/// 如果这个过程 结果为 1,那么这个数就是快乐数。
/// @param n
/// @return n是快乐数则返回true,否则false
bool isHappy(int n){
unordered_set<int> hashSet;
int res=0;
while(n!=1){
if(hashSet.find(n)==hashSet.end()){
hashSet.insert(n);
}
else{
return false;
}
while(n>0){
res+=pow(n%10,2);
n/=10;
}
n=res;
res=0;
}
return true;
}
};
有了思路就很简单了。。。。
思路一点没有,不快乐了。
1. 两数之和
简单思路是循环套循环,,但是是n方,pass
这个题放到了哈希表的专题下面一定有它的道理,嗯。
为啥哈希啊
看文章吧。。
存放遍历过的元素,,一脸懵逼
不仅需要知道是否遍历过,也需要知道对应下标,,知道这些干啥,懵
看一眼代码,,
找互补的数。
ok重新整理一下思路:题目为两数之和,找数组中的两个值和为target,我们要减少遍历的次数,就需要用一种方法记录已经见过的值,并且能够快速地在已经见过的值中找到一个值用来和当前的值互补。已经记忆过的不重复的值(但是index可能重复),而我们需要的是返回下标,就需要记录下标,map完美匹配。
ok思路整理完毕,开始编码
class Solution1{
public:
/// @brief 两数之和,好精妙的哈希,找出数组nums中两个数的下标,这两个数的和为target
/// @param nums
/// @param target
/// @return 返回两个数下标的数组
vector<int> twoSum(vector<int>& nums,int target){
unordered_map<int,int> hashMap;
int temp=0;
for(int i=0;i<nums.size();i++){
temp=target-nums[i];
auto it=hashMap.find(temp);
if(it!=hashMap.end()){
//说明找到了
return {it->second,i};
}
hashMap[nums[i]]=i;
}
return {};
}
};
哈希真的很美妙