哈希表的适用场景与使用方法
哈希表适用场景:
哈希表适用场景:用于快速判断一个元素是否出现在集合里。
常见方法:
常见三的种哈希结构:数组、集合(set)、映射(map)
数组:
数组是最简单的哈希表,但因数组大小有限,不适用于值少、跨度大且分散的情况。
有效的字母异位词
#include <iostream>
#include <string.h>
using namespace std;
int main() {
string s, t;
cin >> s >> t;
int recode[26] = {0}; //题目可知只包含小写字母,固大小设置为26
for (int i = 0; i < s.size(); i++) {
recode[s[i] - 'a']++; //将各字母按顺放入recode,并记录次数
}
for (int j = 0; j < t.size(); j++) {
recode[s[j] - 'a']--; //每找一次,减一
}
for (int i = 0; i < 26; i++) {
if (recode[s[i]] != 0)
return 0;
}
return 1;
}
赎金信
分析:
“只包含小写字母”!!!!
固用长度为26的数组来解决该问题最为合适
①以字母为下表,以值来记录次数
②若找到目标值则次数减一,若次数小于0则返回false
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
if(ransomNote.size()>magazine.size()) return false;
int record[26]={0};
for(int i=0;i<magazine.size();i++) record[magazine[i]-'a']++;
for(int j=0;j<ransomNote.size();j++){
if(record[ransomNote[j]-'a']!=0) record[ransomNote[j]-'a']--;
else return false;
}
return true;
}
};
集合(set)
主要使用set,来解决值少、跨度大且分散的情况。
C++中共有三种可用set:
std::set
std::multiset
std::unordered_set
std::set与std::multiset的底层实现是红黑树,std::unordered_set的底层实现是哈希表,固选用std::unordered_set的效率最高。
std::unordered_set适用于以下场景:
- 快速查找 (即哈希)
- 无序
- 去重
两个数组的交集
#include <iostream>
#include <string.h>
#include <unordered_set>
#include <vector>
using namespace std;
int main() {
vector<int> nums1;
vector<int> nums2;
unordered_set<int> result;
unordered_set<int> num1(nums1.begin(), nums1.end());
// 将nums1中的值传入set(为实现快速查找与去重)
for (int num : nums2) {
if (num1.find(num) != num1.end())
result.insert(num);
//若在nums2的值在num1中被找到,就插入结果中
}
//结果返回result,因为是自己编译器写的所以只能返回1了
//return vector<int>(result.begin(),result.end());
return 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;
if(set.find(sum)!=set.end()) return false;
else set.insert(sum);
n=sum;
}
}
};
映射(map)
两数之和
分析:
该题需要:①遍历元素找到目标值②记录下标并返回
固此种情形用map较为合适,map:map[key]=values (有些像Python中的字典)
用key来存放元素,values存放下标
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> map;
for(int i=0;i<nums.size();i++){
auto it=map.find(target-nums[i]);//it此时为:it[key]=values
if(it!=map.end()) return {it->second,i};//it->first=key,it->second=values
else map.insert(pair<int,int>(nums[i],i));//若未找到则将该值和其下标插入map,用于后续查找
}
return{};
}
};
四数相加
该题为哈希经典题目
分析:
可将该题分为2数之和,固需将nums1和nums2的和为第一个数x,将nums3和nums4的和为第二个数y。
①以x为key,以其出现的次数为values
②在map中找(0-(x)),若找到则result+=map[0-(x)]
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int> map;
for(int a:nums1){
for(int b:nums2)
map[a+b]++;//以num1和num2的和为key,以和的次数为values
}
int count=0;
for(int c:nums3){
for(int d:nums4)
if(map.find(0-(c+d))!=map.end()) count+=map[0-(c+d)];
}
return count;
}
};