哈希理论基础
哈希解决的主要问题: 快速的判断一个元素是出现在集合里。
总结: 遇到快速判断一个元素是否在集合中,就要考虑哈希法。
242.有效的字母异位词
题目链接: 242.有效的字母异位词
思路1: 利用数组作为哈希表,将字符串的每一个 字母 - ‘a’ 映射到相应的数组位置,再循环遍历另一个字符串,对应到数组位置,每次减1,最后统计一下数组每一个位置,若都是0则互为字母异位词,反之则不是。
代码如下:
class Solution {
public:
bool isAnagram(string s, string t) {
int res[26] = {0};
for(int i = 0; i < s.size(); i++){
int x = s[i] - 'a';
res[x]++;
}
for(int i = 0; i < t.size(); i++){
int x = t[i] - 'a';
res[x]--;
}
for(auto c : res){
if(c) return false;
}
return true;
}
};
思路2: 利用两个unordered_map来记录每个字符串中每个字母的数量,最后相互比较(unordered_map的比较是字典意义的比较,会逐个比较每一个元素)
代码如下:
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char,int> hash0,hash1;
for(auto c : s) hash0[c]++;
for(auto c : t) hash1[c]++;
return hash0 == hash1;
}
};
349. 两个数组的交集
题目链接: 349. 两个数组的交集
思路: 利用unordered_set,首先遍历第一个数组将其中的元素放入到set中,再遍历第二个数组,遍历的过程中查看set中是否有一样的元素,有则将其放入vector 并将其在set中删除,最终得到res数组便是交集。
代码如下:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> set;
vector<int> res;
for(int i = 0; i < nums1.size(); i++) set.insert(nums1[i]);
for(int i = 0; i < nums2.size(); i++){
if(set.count(nums2[i])){
res.push_back(nums2[i]);
set.erase(nums2[i]);
}
}
return res;
}
};
202. 快乐数
题目链接: 202. 快乐数
思路1: 本题有一定的思维难度,题目规定数据大小不超过2^31 - 1,即每个位置均为9,每操作依次最大会变成810,即所有数都会变成0~810中的任意一个,且当某一个数第二次出现的时候,就会陷入一个循环,同环形链表: 环形链表
我们的目标是看这个环中是否有1,若有1则这个环中的元素全都是1,若无1,则这个数不是快乐数。(快慢指针,slow每次操作一遍,fast每次操作两遍)
代码如下:
class Solution {
public:
int get(int x){
int res = 0;
while(x){
res += (x % 10) * (x % 10);
x/=10;
}
return res;
}
bool isHappy(int n) {
int fast = get(n),slow = n;
while(fast != slow){
fast = get(get(fast));//操作两遍
slow = get(slow);//操作一遍
}
return fast == 1;
}
};
思路二: 题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
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;
}
}
};
1. 两数之和
题目链接: 1. 两数之和
思路: 遍历数组,将每个数组元素的下标存在map里,在遍历的过程中查看map是否存在target - num[i] ,若存在将两者的下标均放入res数组中,否则就将该元素放入map中
代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map;
vector<int> res;
for(int i = 0; i < nums.size(); i++){
int n = target - nums[i];
if(map.count(n)){
res.push_back(i);
res.push_back(map[n]);
}
map[nums[i]] = i;
}
return res;
}
};