基础知识
哈希表是一种根据关键码的值直接访问数据的数据结构。一般用来快速判断一个元素是否出现在集合中。
哈希函数
hashCode通过特定编码格式,可以将其他数据格式转化为不同的数值。然后哈希函数把这些值映射在哈希表的索引上。
哈希碰撞
遇到哈希碰撞后,有两种解决方法:
拉链法:将冲突的值依次存储在链表中。
线性探测法:将冲突的值存储在下一个空位,因此必须保证 tableSize 大于 dataSize 。
三种哈希结构
分别是:数组、集合(set)、映射(map)
当我们使用集合解决哈希问题的时候,优先使用 unordered_set
,因为它的查询和增删效率最优;
若要求集合有序,就使用 set
;
若要求集合不仅有序,还要有重复数据,就使用 multiset
。
前者的底层实现用哈希表,后两者用红黑树
有效的字母异位词
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++) {
if (record[i] != 0) {
return false;
}
}
return true;
}
};
两个数组的交集
用 unordered_set
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; // 保存结果
unordered_set<int> nums_set(nums1.begin(), nums1.end()); // 去重
for (int num : nums2) {
// find()查找该元素第一次出现的位置,end()指向末尾元素的下一个位置
if (nums_set.find(num) != nums_set.end()) { // 说明找到了
result_set.insert(num); // 放入交集
}
}
return vector<int>(result_set.begin(), result_set.end()); // 这里用vector
}
};
两数之和
暴力法
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++) {
for (int j = i + 1; j < nums.size(); j++) {
if (nums[i] + nums[j] == target) {
return {i, j};
}
}
}
return {};
}
};
时间复杂度:O(n^2)
Map
在本题中,用数组不好,因为元素很少;也不适用 set ,因为 set 只保存一个 key ,但我们既要比较值,同时保存下标。
故选用 map ,<key, value> 用 key 表示值,用 value 记录下标。
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 iter = map.find(target - nums[i]); // auto 自己推演数据类型
if (iter != map.end()) { // 找到一个
return {i, iter->second}; // first表示key,second表示value
}
map.insert(pair<int, int>(nums[i], i)); // map<X,Y>实际存储的是pair<const X,Y>
}
return {};
}
};
时间复杂度:O(n)
四数相加
原式可转化为 nums1[i] + nums2[j] = -nums3[k] - nums4[l]
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map <int, int> umap;
for (int a : nums1) {
for (int b : nums2) {
umap[a + b]++;
}
}
// 找0 - (c + d)
int count = 0;
for (int c : nums3) {
for (int d : nums4) {
if (umap.find(0 - (c + d)) != umap.end()) {
count += umap[0 - (c + d)];
}
}
}
return count;
}
};
三数之和
哈希解法
输出结果与预期结果不符,不能吧。挨个对了一遍,没错啊
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0) break;
if (i > 0 && nums[i - 1] == nums[i]) { // 元素a去重
continue;
}
unordered_set<int> set;
for (int j = i + 1; j < nums.size(); j++) {
if (j > i + 2 && nums[j - 2] == nums[j - 1] && nums[j - 1] == nums[j]) { // 元素b去重
continue;
}
int c = 0 - (nums[i] + nums[j]);
if (set.find(c) != set.end()) {
result.push_back({nums[i], nums[j], c});
set.erase(c); // 元素c去重
} else {
set.insert(nums[j]) // 不懂
}
}
}
return result;
}
};
双指针法
学不懂了,先放着