1.哈希表 Hash table
https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
当我们要快速判断一个元素是否出现在集合里的时候,就要考虑哈希法。
定义:哈希表是根据关键码的值而直接进行访问的数据结构。如数组。
1.1 哈希函数
把值映射到哈希表的索引上。
如想知道某学生是否存在学校里,首先先将全校学生名字存在哈希表里。通过hashcode把名字转为数值,hashcode是通过特定编码方式将不同数据格式转化成不同数值。将这个数字再对哈希表的大小取模,即为下标。而当学生数量大于哈希表大小时,就会发生哈希碰撞。
比如两个学生映射到同一个下标,解决方法有拉链法和线性探测法。
拉链法:碰撞的位置创建链表存储多余的元素。
线性探测法:选一个放入碰撞的下标,其余元素往下找空位。tabelsize>datasize
2 有效的字母异位词 LeetCode 题242
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
来源:力扣(LeetCode)
https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D.html#%E6%80%9D%E8%B7%AF
此处注意recode[s[i]-‘a’]运用了哈希表的定义,字符转成了下标。
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26] = {0};
for (int i = 0; i < s.size(); i++) {
// 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
record[s[i] - 'a']++;
}
for (int i = 0; i < t.size(); i++) {
record[t[i] - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (record[i] != 0) {
// record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
return false;
}
}
// record数组所有元素都为零0,说明字符串s和t是字母异位词
return true;
}
};
3.两个数组的交集 LeetCode 题 349
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86.html#_349-%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86
当我们要快速判断一个元素是否出现在集合里的时候,就要考虑哈希法。而用什么结构的哈希法,如果哈希值比较少,特别分散,跨度很大,使用数组类型的哈希表就比较浪费空间。此时可以用set结构体。
对于set,C++中有std::set 、std::multiset、std::unordered。
前两个底层实现是红黑树,后一个是哈希表。输出可以不按顺序,故采用std::unordered_set实现。
if (num_set.find(num) != num_set.end()) 查找num是否在num_set里。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
unordered_set<int> 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<int>(result_set.begin(), result_set.end());
}
};
4 快乐数 LeetCode 题202
https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
分析:题目说会无限循环也就是说有个sum重复出现了,以至于第二轮循环继续求该快乐数。判断元素是否出现在集合里(其实也相当于判断元素是否重复),用哈希法。判断sum是否重复出现就可以使用unordered_set。取个位数的操作要详记。
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> set;
while(1) {
int sum = getSum(n);
if (sum == 1) {
return true;
}
// 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
if (set.find(sum) != set.end()) {
return false;
} else {
set.insert(sum);
}
n = sum;
}
}
};