基本数据结构
Leetcode.1两数之和
Leetcode.187重复的DNA序列
Leetcode.706设计哈希映射
Leetcode.652寻找重复的子树
Leetcode.560和为 K 的子数组
Leetcode.547省份数量
Leetcode.684冗余连接
Leetcode.692前K个高频单词
Leetcode.295数据流的中位数
Leetcode.352将数据流变为多个不相交区间
一、Leetcode.1两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int>hash;
for(int i=0;i<nums.size();i++){
if(hash.count(target-nums[i]))return {hash[target-nums[i]],i};
hash[nums[i]]=i;
}
return {-1,-1};
}
二、Leetcode.187重复的DNA序列
DNA序列 由一系列核苷酸组成,缩写为 ‘A’, ‘C’, ‘G’ 和 ‘T’.。
例如,“ACGAATTCCG” 是一个 DNA序列 。
在研究 DNA 时,识别 DNA 中的重复序列非常有用。
给定一个表示 DNA序列 的字符串 s ,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。
vector<string> findRepeatedDnaSequences(string s) {
unordered_map<string,int>hash;
vector<string>ans;
for(int i=0;i+9<=s.size()-1;i++){
string str=s.substr(i,10);
hash[str]++;
if(hash[str]==2)ans.push_back(str);
}
return ans;
}
三、Leetcode.706设计哈希映射
不使用任何内建的哈希表库设计一个哈希映射(HashMap)。
int N=20011;
vector<list<pair<int,int>>>h;
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())return;
else h[t].erase(it);
}
四、Leetcode.652寻找重复的子树
给定一棵二叉树 root,返回所有重复的子树。
对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。
如果两棵树具有相同的结构和相同的结点值,则它们是重复的。
unordered_map<string,int>h;
vector<TreeNode*>ans;
//1,2, , ,
string dfs(TreeNode*root){
if(root==NULL)return "";
string str="";
str+=to_string(root->val)+",";
str+=dfs(root->right)+",";
str+=dfs(root->left);
h[str]++;
if(h[str]==2)ans.push_back(root);
return str;
}
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
dfs(root);
return ans;
}
五、Leetcode.560和为 K 的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
int subarraySum(vector<int>& nums, int k) {
unordered_map<int,int>h;
int sum=0;
h[0]=1;
int ans=0;
for(int i=0;i<nums.size();i++){
sum+=nums[i];
ans+=h[sum-k];
h[sum]++;
}
return ans;
}
六、Leetcode.547省份数量
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
vector<int>p;
int find(int x){
if(x!=p[x])p[x]=find(p[x]);
return p[x];
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n=isConnected.size();
p=vector<int>(n);
for(int i=0;i<n;i++)p[i]=i;
int ans=n;
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(isConnected[i][j]==0)continue;
if(find(i)!=find(j)){
p[find(i)]=find(j);
ans--;
}
}
}
return ans;
}
七、Leetcode.684冗余连接
树可以看成是一个连通且 无环 的 无向 图。
给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。
请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案,则返回数组 edges 中最后出现的边。
vector<int>p;
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=i;i<=n;i++)p[i]=i;
for(auto e:edges){
int x=e[0];
int y=e[1];
if(find(x)==find(y))return {x,y};
p[find(x)]=find(y);
}
return {-1,-1};
}
八、Leetcode.692前K个高频单词
给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
unordered_map<string,int>hash;
typedef pair<int,string> PIS;
priority_queue<PIS>heap;
vector<string> topKFrequent(vector<string>& words, int k) {
for(int i=0;i<words.size();i++){
hash[words[i]]++;
}
for(auto item:hash){
PIS t(-item.second,item.first);
heap.push(t);
//cout<<item.second<<item.first<<endl;
if(heap.size()>k){
//cout<<heap.top().second<<endl;
heap.pop();
}
}
vector<string>ans(k);
for(int i=k-1;i>=0;i--){
ans[i]=heap.top().second;
//cout<<ans[k]
heap.pop();
}
return ans;
}
九、Leetcode.295数据流的中位数
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
priority_queue<int>down;
priority_queue<int,vector<int>,greater<int>>up;
MedianFinder() {
}
void addNum(int num) {
if(down.empty()||num>=down.top())up.push(num);
else{
down.push(num);
up.push(down.top());
down.pop();
}
if(up.size()>down.size()+1){
down.push(up.top());
up.pop();
}
}
double findMedian() {
if(down.size()+up.size()&1==1)return up.top();
else return (down.top()+up.top())/2.0;
}
十、Leetcode.352将数据流变为多个不相交区间
给你一个由非负整数 a1, a2, …, an 组成的数据流输入,请你将到目前为止看到的数字总结为不相交的区间列表。
实现 SummaryRanges 类:
SummaryRanges() 使用一个空数据流初始化对象。
void addNum(int val) 向数据流中加入整数 val 。
int[][] getIntervals() 以不相交区间 [starti, endi] 的列表形式返回对数据流中整数的总结。
map<int, int> interval;
SummaryRanges() {}
void addNum(int val) {
auto up = interval.upper_bound(val);
auto down = (up == interval.begin() ? interval.end() : prev(up));
if (down != interval.end() && (val >= down->first && val <= down->second)) {
} else if ((up != interval.end() && up->first - 1 == val) && (down != interval.end() && down->second + 1 == val)) {
int l = down->first, r = up->second;
interval.erase(down->first);
interval.erase(up->first);
interval.emplace(l, r);
} else if (down != interval.end() && down->second + 1 == val) {
int l = down->first, r = val;
interval.erase(l);
interval.emplace(l, r);
} else if (up != interval.end() && up->first - 1 == val) {
int l = val, r = up->second;
interval.erase(up->first);
interval.emplace(l, r);
} else {
interval.emplace(val, val);
}
cout << interval.size() << endl;
}
vector<vector<int>> getIntervals() {
vector<vector<int>> ans;
for (auto& it : interval) {
ans.push_back({it.first, it.second});
}
return ans;
}