什么时候用哈希表?
需要快速找到某个元素是否存在时。
哈希表常用数据结构以及如何选择?
数组:元素所有可能值的范围较短,用一个数组可以将元素所有可能值保存下来,当元素所有可能值范围较大比如上亿个可能值,无法再用连续存储空间来表示就不再适用。
set:仅需要查找某元素是否存在,同时元素可能值范围很大。
map: 需要找到某元素是否存在,同时还要了解这个元素某些属性。
题目链接:242.有效的字母异位词
刚接触这道题想的用map来记录每个字母出现的次数,map可以简化,将每个字母离字符'a'的偏移量来提供数组的索引值。
class Solution {
public:
bool isAnagram(string s, string t) {
vector<int> hash(26, 0);
for(int i = 0; i < s.length(); i++) {
hash[s[i] - 'a']++;
}
for(int i = 0; i < t.length(); i++) {
hash[t[i] - 'a']--;
}
for(int i = 0; i < hash.size(); i++) {
if(hash[i] != 0) return false;
}
return true;
}
};
题目链接:349. 两个数组的交集
对c++标准库中容器使用的不熟练、原理不熟悉导致刚开始写的代码很臃肿,set初始化方式很笨:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> hash;
vector<int> result;
for(size_t i = 0; i < nums1.size(); i++) {
if(hash.find(nums1[i]) == hash.end()) {
hash.insert(nums1[i]);
}
}
for(size_t i = 0; i < nums2.size(); i++) {
if(hash.find(nums2[i]) != hash.end()){
hash.erase(hash.find(nums2[i]));
result.push_back(nums2[i]);
}
}
return result;
}
};
看了大佬写的代码之后感觉自己写的就像rubbish:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> hash(nums1.begin(), nums1.end());
unordered_set<int> result;
for(int i : nums2) {
if (hash.find(i) != hash.end()) {
result.insert(i);
}
}
return vector<int>(result.begin(), result.end());
}
};
由于这道题规定了nums1与nums2值的范围是[0, 1000],因此可以选用数组来构建哈希表:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> result;
bool hash[1001] = {false};
for(int i : nums1) {
if(!hash[i]) hash[i] = true;
}
for(int i : nums2) {
if(hash[i]) {
result.push_back(i);
hash[i] = false;
}
}
return result;
}
};
题目链接:202. 快乐数
单纯看这道题想不到用hash表,同时不知道为什么如果不收敛到1,一定会陷入死循环,为什么出现过的值会重新出现,而不是每一次结果都不同。
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> hash;
while (hash.find(n) == hash.end()){
if(n == 1) {
return true;
}
hash.insert(n);
n = sum(n);
}
return false;
}
int sum(int n) {
int result = 0;
while(n > 0) {
result += (n % 10) * (n % 10);
n /= 10;
}
return result;
}
};
题目链接: 1. 两数之和
自己写的时候想到用map,没想到一边向map里插入值一边寻找符合条件的值。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash;
for(int i = 0; i < nums.size(); i++) {
hash[nums[i]] = i;
}
for(int i = 0; i < nums.size(); i++) {
if(hash.find(target - nums[i]) != hash.end() && \
hash.find(target - nums[i])->second != i) {
return vector<int> {i, hash.find(target - nums[i])->second};
}
}
return vector<int> {};
}
};
优化之后:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash;
for(int i = 0; i < nums.size(); i++) {
if(hash.find(target - nums[i]) == hash.end()) {
hash[nums[i]] = i;
}
else {
return vector<int>{hash.find(target - nums[i])->second, i};
}
}
return vector<int>{};
}
};