目录
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
我们一般选用下面三种数据结构实现哈希
- 数组
- set
- map
c++的set
集合 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
---|---|---|---|---|---|---|
std::set | 红黑树 | 有序 | 否 | 否 | O(log n) | O(log n) |
std::multiset | 红黑树 | 有序 | 是 | 否 | O(logn) | O(logn) |
std::unordered_set | 哈希表 | 无序 | 否 | 否 | O(1) | O(1) |
当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。
使用数组来做哈希的题目,是因为题目都限制了数值的大小。
而如果题目没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
但是直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。
(摘自代码随想录)
242.有效的字母异位
var isAnagram = function(s, t) {
const base = 'a'.charCodeAt();
const set = new Array(26).fill(0);
for (i of s) {
set[i.charCodeAt() - base]++;
}
for (i of t) {
set[i.charCodeAt() - base]--;
}
for (i of set) {
if (i !== 0) return false;
}
return true;
};
49.字母异位词分组
- 用力扣学c++了,有的地方看了好久才明白(;′⌒`)
- 当时在最后将结果放进vector时,有个疑问为什么存完后vector是个二维数组,后面想到map的值就是一个vector,存一次就是把一整个vector存入了
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> hash;
for (string str:strs) {
string key = str;
sort(key.begin(),key.end()); // 先对字符串排序
hash[key].push_back(str);
}
vector<vector<string>> res;
for (auto i : hash) {
res.push_back(i.second);
}
return res;
}
};
438.找到字符串中所有字母异位词
- 一看题干就想到了滑动窗口
- 没想到vector还能直接用等号这样比较是否相同,学费了
- 没考虑到s长度小于p的情况,下次还是要注意特殊情况
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> sCount(26,0), pCount(26,0), res;
if (s.size() < p.size()) return vector<int>();
for (int i = 0; i < p.size(); i++) pCount[p[i]-'a']++;
int left = 0, right = 0;
for (; right < p.size(); right++) sCount[s[right]-'a']++;
if (sCount == pCount) res.push_back(0);
for (; right < s.size(); right++, left++) {
sCount[s[right]-'a']++;
sCount[s[left]-'a']--;
if (sCount == pCount) res.push_back(left+1);
}
return res;
}
};
349.两个数组的交集
var intersection = function(nums1, nums2) {
const num1Set = new Set(nums1);
const resSet = new Set();
for (let i of nums2) {
num1Set.has(i) && resSet.add(i);
}
return [...resSet];
};
350.两个数组的交集Ⅱ
- 和上一题思路相似
var intersect = function(nums1, nums2) {
if (nums1.length < nums2.length) {
const t = nums1;
nums1 = nums2;
nums2 = t;
}
const m = new Map();
const res = [];
for (let i of nums1) {
m.has(i) ? m.set(i, m.get(i) + 1) : m.set(i, 1);
}
for (let i of nums2) {
if (m.has(i)) {
m.set(i, m.get(i) - 1);
if (m.get(i) === 0) m.delete(i);
res.push(i);
}
}
return res;
};