做提前需要直到哈希表理论基础,了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
文章讲解:代码随想录
242.有效的字母异位词
题目链接/文章讲解/视频讲解: 代码随想录
1.代码展示:
bool isAnagram(string s, string t) {
//考虑到字母a-z为连续的26个字母,因此使用数组就可以
//step1 构造数组
//注意:一定要初始化数组!!!
//否则数组中的值会乱套
int hash[26] = {0};
//step2 统计s中每个字符的个数并记录
for (int i = 0; i < s.size(); i++) {
hash[s[i] - 'a']++;
}
//step3 统计t中每个字符的个数并记录
for (int j = 0; j < t.size(); j++) {
hash[t[j] - 'a']--;
}
//step4 统计hash表内每个字符个数
//数组没有size()函数
for (int k = 0; k < 26; k++) {
if (hash[k] != 0) {
return false;
}
}
return true;
}
2.本题小节
本题之所以选用数组,是因为字母只有26个,需要寻找的范围很小,数组的不同索引对应着不同字母出现的次数,只要直到这点,这题就很好做了。
349. 两个数组的交集
题目链接/文章讲解/视频讲解: 代码随想录
1.代码展现
//349 两个数组的交集
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//方法一 用set来做
//step1 构建储存结果的容器以及处理数据的容器
//注意:包含头文件
unordered_set<int> usResult;
unordered_set<int> usNums(nums1.begin(), nums1.end());
//step2 遍历数组2,通过hash方式查找数组2中的数据
for (int i = 0; i < nums2.size(); i++) {
//查询到
if (usNums.count(nums2[i])) {
//step3 查询到,储存起来
//注意:这里的容器有去重的作用
usResult.insert(nums2[i]);
}
}
return vector<int> (usResult.begin(), usResult.end());
//方法二 用vector来做
unordered_set<int> snResult;
int nNums[1001] = {0};
for (int i = 0; i < nums1.size(); i++) {
//做标记,同时也可以防止重复
nNums[nums1[i]] = 1;
}
for (int i = 0; i < nums2.size(); i++) {
if (nNums[nums2[i]] == 1) {
snResult.insert(nums2[i]);
}
}
return vector<int>(snResult.begin(), snResult.end());
}
2.本题小节
本题既可以用set也可以用数组。首先要注意的是使用 unordered_set的话需要包含头文件“unordered_set”, unordered_set中的值不能重复,因此使用找个容器有去重的作用。本题由于修改了输入的数组长度小于1000,并且数也小于1000,因此也可以使用数组,但是可以看出来,相较于set,数组占用了更多的空间,下标与要寻找的数是可以相同的,因此可以用数组来寻找。
202. 快乐数
题目链接/文章讲解:代码随想录
1.代码展现
//202 快乐数
//求解各个位平方和
int doSqurSum(int n) {
int nSum = 0;
//直到n所有位置都计算过
while (n) {
//step1 计算n中最后一位平方和
nSum += (n % 10) * (n % 10);
//step2 去掉n中最后一位
n /= 10;
}
return nSum;
}
bool isHappy(int n) {
unordered_set<int> nNum_set;
int nSum;
while (1) {
//step1 计算各个位数平方和
nSum = doSqurSum(n);
//step2 判断sum是否为1
if (nSum == 1) {
return true;
}
//step3 如果sum出现过,那么久证明
//该数不为快乐数
if (nNum_set.count(nSum)) {
return false;
}
else {
nNum_set.insert(nSum);
}
//step4 重新给n赋值
n = nSum;
}
}
2.本题小节
首先要知道各个数的平方和如何计算,如上述代码,从各位开始算,然后是如何处理计算后的数,有三种情况,如果1,那么就满足快乐数,返回为真;如果出现过,那么不可能为快乐数,返回假,如果以上情况都不满足,那么给n赋值继续算,直到满足上面的一种情况。
这里要注意的就是出现过这种情况用到了哈希表,由于不知道找个数是多大,也不知道需要计算多少次(表的长度),因此就使用unordered_set来储存计算后的结果。
1. 两数之和
题目链接/文章讲解/视频讲解:代码随想录
1.代码展示
//1 两数之和
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map <int ,int> mnNums;
for (int i = 0; i < nums.size(); i++) {
int nTemp = target - nums[i];
if (mnNums.count(nTemp)) {
return {mnNums.find(nTemp)->second, i};
}
mnNums.insert(make_pair(nums[i], i));
}
return {};
}
2.本题小节
如果要使用哈希表方法的话,就不要被两数之和迷惑,因为这里的和是固定的,因此已知和和另外一个数,那么就可以求要寻找的数。如果找找个数呢,这个时候就要用到哈希表了,由于要返回的是被寻找到数的下表,因此这里用unordered_map,储存数和对应的下表,这里的储存时机很巧妙,可以看出,遍历时第一次寻找值的时候根本不可能找到,因为map中啥也没有,在未找到之后储存当前数及其对应下标,从第二次开始就可以寻找之前的数。
我自己最开始做的是先把数组都储存到map中,然后再寻找数,但是这样会碰到寻找到本身或者是漏掉的情况(当数组中有两个相同的值时),但是使用上述的方式,就不会出现这两种情况。