哈希表专题
242.有效的字母异位词
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char,int> a,b;
for(char x : s) a[x]++;
for(char x : t) b[x]++;
return a == b; //c++中比较哈希表是否相等是注意比较表中元素是否相等
}
};
或者不用c++的STL
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26] = {0};
for(int i = 0;i < s.size();i++){
record[s[i] - 'a']++;
}
for(int i = 0;i < t.size();i++){
record[t[i] - 'a']--;
}
for(int i = 0;i < 26;i++){
// record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
if(record[i] != 0){
return false;
}
}
return true;
}
};
349.两个数组的交集
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> res;
unordered_set<int> Set;
for(int x : nums1) Set.insert(x);
for(int x : nums2){
//发现 nums2 的元素在nums1出现过
if(Set.count(x)){
res.push_back(x);//将其放入答案中
Set.erase(x);//同时将集合中的元素去除
}
}
return res;
}
};
202.快乐数
class Solution {
public:
// 取数值各个位上的单数之和
int get(int n)
{
int res = 0;
while(n != 0){
res += (n % 10) *(n % 10);
n /= 10;
}
return res;
}
bool isHappy(int n) {
//快慢指针 回到了判断链表是否有环问题
int slow = n,fast = get(n);
while(fast != slow)
{
fast = get(get(fast));
slow = get(slow);
}
return fast == 1;
}
};
//当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。
//题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现
//这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
class Solution {
public:
// 取数值各个位上的单数之和
int get(int n)
{
int res = 0;
while(n != 0){
res += (n % 10) * (n % 10);
n /= 10;
}
return res;
}
bool isHappy(int n) {
unordered_set<int> Set;
while(1)
{
int sum = get(n);
if(sum == 1) return true;
// 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
if(Set.count(sum)) return false;
else Set.insert(sum);
//继续下一轮
n = sum;
}
}
};
1.两数之和
class Solution {
public:
unordered_map<int,int> hash;
vector<int> twoSum(vector<int>& nums, int target) {
for(int i = 0;i < nums.size();i++)
{
int r = target - nums[i];
if(hash.count(r))
{
return {i,hash[r]};
}else{
// 如果没找到匹配对,就把访问过的元素和下标加入到hash中
hash[nums[i]] = i;
}
}
return {};
}
};
454.四数之和(II)
class Solution {
public:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
unordered_map<int, int> hash; //key:a+b的数值,value:a+b数值出现的次数
// 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
for (int a : A) {
for (int b : B) {
hash[a + b]++;
}
}
int count = 0; // 统计a+b+c+d = 0 出现的次数
// 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
for (int c : C) {
for (int d : D) {
if (hash.find(0 - (c + d)) != hash.end()) {
count += hash[0 - (c + d)];
}
}
}
return count;
}
};
383.赎金信
// 哈希表
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char,int> hash;
// 遍历 magazine 字符串,用哈希表统计每个字母的出现次数
for(char a : magazine) hash[a]++;
//然后遍历 rason 字符串,如果发现某个字母的次数为0,返回 false;否则对应字母的出现次数减 1。
for(char b : ransomNote){
if(hash[b] == 0) return false;
else hash[b]--;
}
return true;
}
};
// 数组
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
//初始化
int record[26] = {0};
if(ransomNote.size() > magazine.size()) return false;
//通过记录record数据记录 magazine里各个字符出现次数
for(int i = 0;i < magazine.size();i++) record[magazine[i] - 'a']++;
for(int j = 0;j < ransomNote.size();j++){
// 遍历ransomNote,在record里对应的字符个数做--操作
record[ransomNote[j] - 'a']--;
// 如果小于零说明ransomNote里出现的字符,magazine没有
if(record[ransomNote[j] - 'a'] < 0) return false;
}
return true;
}
};
15.三数之和
算法分析
排序 + 双指针
1、枚举每个数,表示该数nums[i]已被确定,在排序后的情况下,通过双指针l,r分别从左边l = i + 1和右边n - 1往中间靠拢,找到nums[i] + nums[l] + nums[r] == 0的所有符合条件的搭配
2、在找符合条件搭配的过程中,假设sum = nums[i] + nums[l] + nums[r]
若sum > 0,则r往左走,使sum变小
若sum < 0,则l往右走,使sum变大
若sum == 0,则表示找到了与nums[i]搭配的组合nums[l]和nums[r],存到ans中
3、判重处理
确定好nums[i]时,l 需要从i + 1开始
当nums[i] == nums[i - 1],表示当前确定好的数与上一个一样,需要直接continue
当找符合条件搭配时,即sum == 0,需要对相同的nums[l]和nums[r]进行判重出来
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
//确定第一个数
for(int i = 0;i < nums.size();i++)
{
// 对第一个数去重
if(i > 0 && nums[i] == nums[i - 1]) continue;
int l = i + 1,r = nums.size() - 1;
while(l < r)
{
int sum = nums[i] + nums[l] + nums[r];
if(sum < 0) l++;
else if(sum > 0) r--;
else {
res.push_back({nums[i],nums[l],nums[r]});
//去重
do {l++;} while (l < r && nums[l] == nums[l - 1]);
do {r--;} while (l < r && nums[r] == nums[r + 1]);
}
}
}
return res;
}
};
18.四数之和
与上面的三数之和思路相同,在上题基础上多了一层循环。
算法分析
排序 + 双指针
1、与三数之和操作类似,枚举每两个数,表示该数nums[i]和nums[j]已被确定,在排序后的情况下,通过双指针l,r分别从左边l = i + 1和右边n - 1往中间靠拢,找到nums[i] + nums[j] + nums[l] + nums[r] == target的所有符合条件的搭配
2、在找符合条件搭配的过程中,假设sum = nums[i] + nums[j] + nums[l] + nums[r]
若sum > target,则r往左走,使sum变小
若sum < target,则l往右走,使sum变大
若sum == target,则表示找到了与nums[i]搭配的组合nums[l]和nums[r],存到ans中
3、判重处理
确定好nums[i]时,l 需要从i + 1开始
当nums[i] == nums[i - 1],表示当前确定好的数与上一个一样,需要直接continue
当nums[j] == nums[j - 1],表示当前确定好的数与上一个一样,需要直接continue
当找符合条件搭配时,即sum == 0,需要对相同的nums[l]和nums[r]进行判重出来
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int i = 0;i < nums.size();i++)
{
if(i > 0 && nums[i] == nums[i - 1]) continue;
for(int j = i + 1;j < nums.size();j++)
{
if(j > i + 1 && nums[j] == nums[j - 1]) continue;
int l = j + 1,r = nums.size() - 1;
while(l < r)
{
//防止溢出
long sum = (long)nums[i] + nums[j] + nums[l] + nums[r];
if(sum > target) r--;
else if(sum < target) l++;
else {
res.push_back({nums[i],nums[j],nums[l],nums[r]});
do{l++;} while(l < r && nums[l] == nums[l - 1]);
do{r--;} while(l < r && nums[r] == nums[r + 1]);
}
}
}
}
return res;
}
};