LeetCode. 基本数据结构
LeetCode.706 设计哈希映射
哈希冲突:哈希冲突就是两个不同值的东西,通过哈希函数计算出来的哈希值相同,这样他们存在数组中的时候就会发生冲突,这就是哈希冲突。
解决哈希冲突的方法:
1.开放地址法
这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。
就是说当发生冲突时,就去寻找下一个空的地址把数据存入其中,只要哈希表足够大,就总能找到这样一个空的地址。
2.拉链法
将所有关键字为同义字的记录存储在一个单链表中。
具体实现:
N = 20011;
vector<list<pair<key, value>>> h(N);
class MyHashMap {
int N = 20011;
vector<list<pair<int, int>>> h;
public:
MyHashMap() {
h = vector<list<pair<int, int>>> (N);
}
list<pair<int, int>>::iterator find(int key) {
int t = key % N;
for(auto it = h[t].begin(); it != h[t].end(); ++it) {
if(it->first == key) return it;
}
return h[t].end();
}
void put(int key, int value) {
auto it = find(key);
int t = key % N;
if(it == h[t].end()) h[t].push_back({key, value});
else it->second = value;
}
int get(int key) {
auto it = find(key);
int t = key % N;
if(it == h[t].end()) return -1;
else return it->second;
}
void remove(int key) {
auto it = find(key);
int t = key % N;
if(it != h[t].end()) h[t].erase(it);
}
};
/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap* obj = new MyHashMap();
* obj->put(key,value);
* int param_2 = obj->get(key);
* obj->remove(key);
*/
LeetCode. 652 寻找重复的子树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
int cnt = 0;
unordered_map<string, int> hash; // 将每个string映射成独一无二的一个int值
unordered_map<int, int> count;
vector<TreeNode*> ans;
public:
string dfs(TreeNode* root) {
if(!root) return to_string(hash["#"]);
auto left = dfs(root->left);
auto right = dfs(root->right);
string tree = to_string(root->val) + ',' + left + ',' + right;
if(!hash.count(tree)) hash[tree] = ++cnt; // 将每个string映射成独一无二的一个int值
int t = hash[tree];
count[t] ++;
if(count[t] == 2) ans.push_back(root);
return to_string(t);
}
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
hash["#"] == ++cnt;
dfs(root);
return ans;
}
};
LeetCode. 560 和为K的子数组
前缀和 + 哈希表
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> hash;
hash[0] = 1;
int res = 0;
for(int i = 0, sum = 0; i < nums.size(); ++i) {
sum += nums[i];
res += hash[sum - k];
++hash[sum]; // 从下标0到下标i的子数组的和为sum的个数,这样可以保证相减之后得到的是连续子数组
}
return res;
}
};
LeetCode. 547 省份数量
class Solution {
vector<int> p;
public:
// 返回x的祖宗节点 + 路径优化
int find(int x) {
if(p[x] != x) p[x] = find(p[x]); // if(不是根节点): 路径压缩
return p[x];
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size();
p = vector<int> (n+1);
for(int i = 1; i <= n; ++i) p[i] = i;
int res = n;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < i; ++j) {
if(isConnected[i][j] == 0) continue;
// isConnected[i][j] == 1: 说明有连接,合并在一起
if(find(i) != find(j)) {
p[find(i)] = find(j); // 合并
res--;
}
}
}
return res;
}
};
LeetCode. 684 冗余连接
class Solution {
vector<int> p;
public:
// find()函数模板:返回x的祖宗结点 + 路径优化
int find(int x) {
if(x != p[x]) p[x] = find(p[x]); // 路径压缩优化
return p[x];
}
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
int n = edges.size();
p = vector<int> (n+1);
for(int i = 1; i <= n; ++i) p[i] = i; // 开始时,每个元素都各自在一个集合内
for(auto e:edges) {
int a = e[0], b = e[1];
if(find(a) == find(b)) return {a, b};
p[find(a)] = find(b); // 合并
}
return {-1, -1};
}
};
LeetCode. 692 前K个高频元素
class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
unordered_map<string, int> hash;
typedef pair<int, string> PIS;
priority_queue<PIS> heap; // 默认大根堆
for(auto word:words) ++hash[word];
for(auto item : hash) {
PIS t(-item.second, item.first);
heap.push(t);
if(heap.size() > k) heap.pop();
}
vector<string> res(k);
for(int i = k - 1; i >= 0; --i) {
res[i] = heap.top().second;
heap.pop();
}
return res;
}
};
LeetCode. 352 将数据流变为多个不相交区间
class SummaryRanges {
map<int, int> L,R;
public:
SummaryRanges() {
}
void addNum(int x) {
if(L.size()) {
auto it = L.lower_bound(x); // 返回第一个值不小于x的位置
if(it != L.end() && it->second <= x) return;
}
int left = L.count(x - 1), right = R.count(x + 1);
if(left && right) {
R[L[x-1]] = R[x+1];
L[R[x+1]] = L[x-1];
L.erase(x-1), R.erase(x+1);
}
else if(left) {
R[L[x-1]] = x;
L[x] = L[x-1];
L.erase(x-1);
}
else if(right) {
L[R[x+1]] = x;
R[x] = R[x+1];
R.erase(x+1);
}
else
R[x] = L[x] = x;
}
vector<vector<int>> getIntervals() {
vector<vector<int>> res;
for(auto item : R) res.push_back({item.first, item.second});
return res;
}
};
/**
* Your SummaryRanges object will be instantiated and called as such:
* SummaryRanges* obj = new SummaryRanges();
* obj->addNum(val);
* vector<vector<int>> param_2 = obj->getIntervals();
*/