学习链接:
- 归并排序详解及应用
- 算法就像搭乐高:带你手撸 LFU 算法
- 前缀树算法模板秒杀五道算法题
- 一道求中位数的算法题把我整不会了
- 单调栈结构解决三道算法题
- 单调队列结构解决滑动窗口问题
- 二叉堆详解实现优先级队列
- 队列实现栈以及栈实现队列
1.数组中的逆序对
题目来源:剑指 Offer 51. 数组中的逆序对
题解:
//官方题解
class Solution {
public:
int mergeSort(vector<int>& nums,vector<int>& tmp,int l,int r){
if(l>=r)
return 0;
int mid=(l+r)/2;
int inv_count=mergeSort(nums,tmp,l,mid)+mergeSort(nums,tmp,mid+1,r);
int i=l,j=mid+1,pos=l;
while(i<=mid&&j<=r){
if(nums[i]<=nums[j]){
tmp[pos]=nums[i];
i++;
inv_count+=(j-mid-1);
}
else{
tmp[pos]=nums[j];
j++;
}
pos++;
}
for (int k = i; k <= mid; ++k) {
tmp[pos++] = nums[k];
inv_count += (j - (mid + 1));
}
for (int k = j; k <= r; ++k) {
tmp[pos++] = nums[k];
}
copy(tmp.begin() + l, tmp.begin() + r + 1, nums.begin() + l);
return inv_count;
}
int reversePairs(vector<int>& nums) {
int n=nums.size();
vector<int> tmp(n);
return mergeSort(nums,tmp,0,n-1);
}
};
//评论题解
int count = 0;
public int reversePairs(int[] nums) {
this.count = 0;
sort(nums, 0, nums.length - 1,new int[nums.length]);
return count;
}
public void sort(int[] nums,int left,int right,int[] temp){
if(left < right){
int mid = (left+right) / 2;//开始递归划分
sort(nums,left,mid,temp);//归并排序左部分(left,mid)
sort(nums,mid+1,right,temp);//归并排序右部分(mid+1,right)
merge(nums,left,mid,right,temp);//合并
}
}
private void merge(int[] nums, int left, int mid, int right, int[] temp) {
int i = left;//左部分首元素
int j = mid + 1;//右部分首元素
int t = 0;
while(i <=mid && j <=right){//在范围之内
if(nums[i] <= nums[j]){
temp[t++] = nums[i++];
}else{
count += (mid - i + 1);//只需要这行代码
temp[t++] = nums[j++];
}
}
while (i <= mid){//右边遍历完事了 左边还剩呢
temp[t++] = nums[i++];
}
while( j <= right){//左边遍历完事了 右边还剩了
temp[t++] = nums[j++];
}
t = 0;//将temp中的元素 全部都copy到原数组里边去
while (left <=right){
nums[left++] = temp[t++];
}
}
2.计算右侧小于当前元素的个数
题目来源:315. 计算右侧小于当前元素的个数
知识点:
- 归并排序
题解:
//题解1:
class Solution {
public:
vector<int> ans;
vector<int> tmp;
vector<int> tmpindex;
vector<int> index;
void mergesort(vector<int>& nums,int l,int r){
if(l>=r) return;
int mid=(l+r)>>1;
mergesort(nums,l,mid);
mergesort(nums,mid+1,r);
merge(nums,l,mid,r);
}
void merge(vector<int>& nums,int l,int mid,int r){
int i=l,j=mid+1,p=l;
while(i<=mid&&j<=r){
if(nums[i]<=nums[j]){
tmp[p]=nums[i];
tmpindex[p]=index[i];
ans[index[i]]+=j-mid-1;
i++;
p++;
}
else{
tmp[p]=nums[j];
tmpindex[p]=index[j];
j++;
p++;
}
}
while(i<=mid){
tmp[p]=nums[i];
tmpindex[p]=index[i];
ans[index[i]]+=j-mid-1;
i++;
p++;
}
while(j<=r){
tmp[p]=nums[j];
tmpindex[p]=index[j];
j++;
p++;
}
for(int k=l;k<=r;k++){
index[k]=tmpindex[k];
nums[k]=tmp[k];
}
}
vector<int> countSmaller(vector<int>& nums) {
int n=nums.size();
ans.resize(n,0);
tmp.resize(n);
tmpindex.resize(n);
index.resize(n);
for(int i=0;i<n;i++){
index[i]=i;
}
mergesort(nums,0,n-1);
return ans;
}
};
//题解2:
class Solution {
public:
vector<int> countSmaller(vector<int>& nums) {
vector<int>count;//保存结果
vector<pair<int,int> > num;//关联每个数和它的序号
for(int i =0;i<nums.size();++i)
{
count.push_back(0);
num.push_back(make_pair(nums[i],i));//保存每个数和它在原数组中的序号,以免在排序过程中打乱顺序
}
merge_sort(num,count);
return count;
}
//归并排序
void merge_sort(vector<pair<int,int> >& vec, vector<int>& count)
{
if(vec.size()<2)
return;
int mid = vec.size()/2;
vector<pair<int,int> > sub_vec1;
vector<pair<int,int> > sub_vec2;
for(int i =0;i<mid;++i)
sub_vec1.push_back(vec[i]);
for(int i =mid;i< vec.size();++i)
sub_vec2.push_back(vec[i]);
merge_sort(sub_vec1,count);
merge_sort(sub_vec2,count);
vec.clear();
merge(sub_vec1,sub_vec2,vec,count);
}
//合并两数组
void merge(vector<pair<int,int> >& sub_vec1,vector<pair<int,int> >& sub_vec2, vector<pair<int,int> >& vec, vector<int>& count)
{
int i =0;
int j =0;
while(i < sub_vec1.size() && j < sub_vec2.size())
{
if(sub_vec1[i].first <= sub_vec2[j].first )
{
vec.push_back(sub_vec1[i]);
count[sub_vec1[i].second] += j;//这句话和下面注释的地方就是这道题和归并排序的主要不同之处
i++;
}else{
vec.push_back(sub_vec2[j]);
j++;
}
}
for(;i<sub_vec1.size();++i)
{
vec.push_back(sub_vec1[i]);
count[sub_vec1[i].second] += j;// -。-
}
for(;j<sub_vec2.size();++j)
{
vec.push_back(sub_vec2[j]);
}
}
};
3.翻转对
题目来源:493.翻转对
题解:
class Solution {
public:
int ans=0;
vector<int> temp;
void mergesort(vector<int>& nums,int left,int right){
if(left>=right) return;
int mid=(left+right)>>1;
mergesort(nums,left,mid);
mergesort(nums,mid+1,right);
merge(nums,left,mid,right);
}
void merge(vector<int>& nums,int left,int mid,int right){
for(int i=left;i<=right;i++)
temp[i]=nums[i];
int i=left,j=mid+1,pos=left;
for(int k=left;k<=mid;k++){
while(j<=right&&(long)nums[k]>(long)nums[j]*2){
j++;
}
ans+=j-mid-1;
}
j=mid+1;
while(i<=mid&&j<=right){
if(temp[i]<=temp[j])
{
nums[pos]=temp[i];
i++;
pos++;
}
else
{
nums[pos]=temp[j];
j++;
pos++;
}
}
while(i<=mid){
nums[pos]=temp[i];
i++;
pos++;
}
while(j<=right){
nums[pos]=temp[j];
j++;
pos++;
}
}
int reversePairs(vector<int>& nums) {
int n=nums.size();
temp.resize(n);
mergesort(nums,0,n-1);
return ans;
}
};
4.区间和的个数
题目来源:327.区间和的个数
题解:
//官方题解
class Solution {
public:
int countRangeSumRecursive(vector<long>& sum, int lower, int upper, int left, int right) {
if (left == right) {
return 0;
} else {
int mid = (left + right) / 2;
int n1 = countRangeSumRecursive(sum, lower, upper, left, mid);
int n2 = countRangeSumRecursive(sum, lower, upper, mid + 1, right);
int ret = n1 + n2;
// 首先统计下标对的数量
int i = left;
int l = mid + 1;
int r = mid + 1;
while (i <= mid) {
while (l <= right && sum[l] - sum[i] < lower) l++;
while (r <= right && sum[r] - sum[i] <= upper) r++;
ret += (r - l);
i++;
}
// 随后合并两个排序数组
vector<long> sorted(right - left + 1);
int p1 = left, p2 = mid + 1;
int p = 0;
while (p1 <= mid || p2 <= right) {
if (p1 > mid) {
sorted[p++] = sum[p2++];
} else if (p2 > right) {
sorted[p++] = sum[p1++];
} else {
if (sum[p1] < sum[p2]) {
sorted[p++] = sum[p1++];
} else {
sorted[p++] = sum[p2++];
}
}
}
for (int i = 0; i < sorted.size(); i++) {
sum[left + i] = sorted[i];
}
return ret;
}
}
int countRangeSum(vector<int>& nums, int lower, int upper) {
long s = 0;
vector<long> sum{0};
for(auto& v: nums) {
s += v;
sum.push_back(s);
}
return countRangeSumRecursive(sum, lower, upper, 0, sum.size() - 1);
}
};
5.LRU 缓存
题目来源:146. LRU 缓存
参考:算法就像搭乐高:带你手撸 LRU 算法
题解:
struct Node {
int key, val;
Node* next;
Node* prev;
Node():key(0),val(0),prev(nullptr),next(nullptr){}
Node(int k, int v):key(k),val(v),prev(nullptr),next(nullptr){}
};
class LRUCache {
public:
unordered_map<int,Node*> cache;
Node* head;
Node* tail;
int size;
int cap;
LRUCache(int capacity):cap(capacity),size(0) {
head=new Node();
tail=new Node();
head->next=tail;
tail->prev=head;
}
int get(int key) {
if(!cache.count(key))
return -1;
Node* node=cache[key];
moveTohead(node);
return node->val;
}
void put(int key, int value) {
if(!cache.count(key)){
Node* node=new Node(key,value);
cache[key]=node;
addToHead(node);
size++;
if(size>cap){
Node* removed=removeTail();
cache.erase(removed->key);
delete removed;
size--;
}
}
else{
Node* node=cache[key];
node->val=value;
moveTohead(node);
}
}
void addToHead(Node* node){
node->prev=head;
node->next=head->next;
head->next->prev=node;
head->next=node;
}
void removeNode(Node* node){
node->prev->next=node->next;
node->next->prev=node->prev;
}
void moveTohead(Node* node){
removeNode(node);
addToHead(node);
}
Node* removeTail(){
Node* node=tail->prev;
removeNode(node);
return node;
}
};
6. LFU缓存
题目来源:460.LFU缓存
题解:
struct Node {
int cnt, time, key, value;
Node(int _cnt, int _time, int _key, int _value):cnt(_cnt), time(_time), key(_key), value(_value){}
bool operator < (const Node& rhs) const {
return cnt == rhs.cnt ? time < rhs.time : cnt < rhs.cnt;
}
};
class LFUCache {
// 缓存容量,时间戳
int capacity, time;
unordered_map<int, Node> key_table;
set<Node> S;
public:
LFUCache(int _capacity) {
capacity = _capacity;
time = 0;
key_table.clear();
S.clear();
}
int get(int key) {
if (capacity == 0) return -1;
auto it = key_table.find(key);
// 如果哈希表中没有键 key,返回 -1
if (it == key_table.end()) return -1;
// 从哈希表中得到旧的缓存
Node cache = it -> second;
// 从平衡二叉树中删除旧的缓存
S.erase(cache);
// 将旧缓存更新
cache.cnt += 1;
cache.time = ++time;
// 将新缓存重新放入哈希表和平衡二叉树中
S.insert(cache);
it -> second = cache;
return cache.value;
}
void put(int key, int value) {
if (capacity == 0) return;
auto it = key_table.find(key);
if (it == key_table.end()) {
// 如果到达缓存容量上限
if (key_table.size() == capacity) {
// 从哈希表和平衡二叉树中删除最近最少使用的缓存
key_table.erase(S.begin() -> key);
S.erase(S.begin());
}
// 创建新的缓存
Node cache = Node(1, ++time, key, value);
// 将新缓存放入哈希表和平衡二叉树中
key_table.insert(make_pair(key, cache));
S.insert(cache);
}
else {
// 这里和 get() 函数类似
Node cache = it -> second;
S.erase(cache);
cache.cnt += 1;
cache.time = ++time;
cache.value = value;
S.insert(cache);
it -> second = cache;
}
}
};
7.实现 Trie (前缀树)
题目来源:208. 实现 Trie (前缀树)
题解:
class Trie {
public:
vector<Trie*> children;
bool isEnd;
Trie* searchPrefix(string prefix){
Trie* node=this;
for(char ch:prefix){
ch-='a';
if(node->children[ch]==nullptr)
return nullptr;
node=node->children[ch];
}
return node;
}
Trie() :children(26),isEnd(false){}
void insert(string word) {
Trie* node=this;
for(char ch:word){
ch-='a';
if(node->children[ch]==nullptr)
node->children[ch]=new Trie();
node=node->children[ch];
}
node->isEnd=true;
}
bool search(string word) {
Trie* node=this->searchPrefix(word);
return node!=nullptr&&node->isEnd;
}
bool startsWith(string prefix) {
return this->searchPrefix(prefix)!=nullptr;
}
};
//自己写的
class Trie {
public:
vector<Trie*> child;
bool isEnd;
/** Initialize your data structure here. */
Trie():child(26),isEnd(false){
}
/** Inserts a word into the trie. */
void insert(string word) {
Trie *node=this;
for(char ch:word){
ch-='a';
if(node->child[ch]==nullptr)
node->child[ch]=new Trie();
node=node->child[ch];
}
node->isEnd=true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
Trie *node=this;
for(char ch:word){
ch-='a';
if(node->child[ch]==nullptr)
return false;
node=node->child[ch];
}
return node->isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie *node=this;
for(char ch:prefix){
ch-='a';
if(node->child[ch]==nullptr)
return false;
node=node->child[ch];
}
return true;
}
};
8.单词替换
题目来源:648. 单词替换
题解:
struct Trie {
unordered_map<char, Trie *> children;
};
class Solution {
public:
string replaceWords(vector<string>& dictionary, string sentence) {
Trie *trie = new Trie();
for (auto &word : dictionary) {
Trie *cur = trie;
for (char &c: word) {
if (!cur->children.count(c)) {
cur->children[c] = new Trie();
}
cur = cur->children[c];
}
cur->children['#'] = new Trie();
}
vector<string> words = split(sentence, ' ');
for (auto &word : words) {
word = findRoot(word, trie);
}
string ans;
for (int i = 0; i < words.size() - 1; i++) {
ans.append(words[i]);
ans.append(" ");
}
ans.append(words.back());
return ans;
}
vector<string> split(string &str, char ch) {
int pos = 0;
int start = 0;
vector<string> ret;
while (pos < str.size()) {
while (pos < str.size() && str[pos] == ch) {
pos++;
}
start = pos;
while (pos < str.size() && str[pos] != ch) {
pos++;
}
if (start < str.size()) {
ret.emplace_back(str.substr(start, pos - start));
}
}
return ret;
}
string findRoot(string &word, Trie *trie) {
string root;
Trie *cur = trie;
for (char &c : word) {
if (cur->children.count('#')) {
return root;
}
if (!cur->children.count(c)) {
return word;
}
root.push_back(c);
cur = cur->children[c];
}
return root;
}
};
9.键值映射
题目来源:677.键值映射
题解:
- 暴力穷举
- 前缀和
- 字典树
//暴力穷举法
class MapSum {
unordered_map<string,int> map;
public:
MapSum() {
}
void insert(string key, int val) {
map[key]=val;
}
int sum(string prefix) {
int res=0;
for(auto &[key,val]:map){
if(key.substr(0,prefix.size())==prefix)
res+=val;
}
return res;
}
};
//前缀哈希和
class MapSum {
unordered_map<string,int> map;
unordered_map<string,int> prefixmap;
public:
MapSum() {
}
void insert(string key, int val) {
int delta=val;
if(map.count(key))
delta-=map[key];
map[key]=val;
for(int i=1;i<=key.size();i++){
prefixmap[key.substr(0,i)]+=delta;
}
}
int sum(string prefix) {
return prefixmap[prefix];
}
};
//字典树
struct TrieNode {
int val;
TrieNode * next[26];
TrieNode() {
this->val = 0;
for (int i = 0; i < 26; ++i) {
this->next[i] = nullptr;
}
}
};
class MapSum {
public:
MapSum() {
this->root = new TrieNode();
}
void insert(string key, int val) {
int delta = val;
if (cnt.count(key)) {
delta -= cnt[key];
}
cnt[key] = val;
TrieNode * node = root;
for (auto c : key) {
if (node->next[c - 'a'] == nullptr) {
node->next[c - 'a'] = new TrieNode();
}
node = node->next[c - 'a'];
node->val += delta;
}
}
int sum(string prefix) {
TrieNode * node = root;
for (auto c : prefix) {
if (node->next[c - 'a'] == nullptr) {
return 0;
} else {
node = node->next[c - 'a'];
}
}
return node->val;
}
private:
TrieNode * root;
unordered_map<string, int> cnt;
};
----------------------------------------------单调栈-------------------------------------------------------
10.移掉k位数字
题目来源:402.移掉k位数字
题解:
class Solution {
public:
string removeKdigits(string num, int k) {
vector<char> stk;
for(auto & digit:num){
while(stk.size()>0&&stk.back()>digit&&k){
stk.pop_back();
k--;
}
stk.push_back(digit);
}
while(k){
stk.pop_back();
k--;
}
string ans="";
bool flag=true;
for(auto &digit:stk){
if(flag&&digit=='0')
continue;
flag=false;
ans+=digit;
}
return ans==""?"0":ans;
}
};
11.股票价格跨度
题目来源:901. 股票价格跨度
题解:
class StockSpanner {
public:
stack<pair<int,int>> st;
int idx;
StockSpanner() {
this->st.emplace(-1,INT_MAX);
this->idx=-1;
}
int next(int price) {
idx++;
while(price>=st.top().second)
st.pop();
int ret=idx-st.top().first;
st.emplace(idx,price);
return ret;
}
};
12.环形子数组的最大和
题目来源:918. 环形子数组的最大和
题解:
- 网络解法
- 单调队列
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int total = 0, maxSum = nums[0], curMax = 0, minSum = nums[0], curMin = 0;
for (int& a : nums) {
curMax = max(curMax + a, a);
maxSum = max(maxSum, curMax);
curMin = min(curMin + a, a);
minSum = min(minSum, curMin);
total += a;
}
return maxSum > 0 ? max(maxSum, total - minSum) : maxSum;
}
};
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int n=nums.size();
vector<int> p(2*n+1);
for(int i=0;i<2*n;i++)
p[i+1]=p[i]+nums[i%n];
int ans=nums[0];
deque<int> dq;
dq.push_back(0);
for(int i=1;i<=2*n;i++){
if(dq.front()<i-n)
dq.pop_front();
ans=max(ans,p[i]-p[dq.front()]);
while(!dq.empty()&&p[i]<=p[dq.back()])
dq.pop_back();//****稍微理解****:队列存最小的前缀和p[j],所以p[i]-p[j]就是最大和!
dq.push_back(i);
}
return ans;
}
};
13.队列中可以看到的人数
题目来源:1944. 队列中可以看到的人数
题解:
class Solution {
public:
vector<int> canSeePersonsCount(vector<int>& heights) {
int n=heights.size();
vector<int> ans(n);
stack<int> st;
for(int i=n-1;i>=0;i--){
while(!st.empty()){
ans[i]++;
if(heights[i]>heights[st.top()])
st.pop();
else
break;
}
st.push(i);
}
return ans;
}
};
14.接雨水(单调栈版)
题目来源:42. 接雨水
题解:
class Solution {
public:
int trap(vector<int>& height) {
int ans=0;
stack<int> st;
int n=height.size();
for(int i=0;i<n;i++){
while(!st.empty()&&height[i]>height[st.top()]){
int top=st.top();
st.pop();
if(st.empty())
break;
int left=st.top();
int curwidth=i-left-1;
int curheight=min(height[left],height[i])-height[top];
ans+=curwidth*curheight;
}
st.push(i);
}
return ans;
}
};
----------------------------------------------单调队列----------------------------------------------------
15.滑动窗口最大值
题目来源:239. 滑动窗口最大值
知识点:
双向队列: C++ STL deque容器(详解版)
deque q;
q.back()
q.pop_back();
q.push_back(i);
q.front();
q.pop_front();
题解:
- 双向队列
- 优先队列
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n=nums.size();
deque<int> q;
for(int i=0;i<k;i++){
while(!q.empty()&&nums[i]>=nums[q.back()])
q.pop_back();
q.push_back(i);
}
vector<int> ans={nums[q.front()]};
for(int i=k;i<n;i++){
while(!q.empty()&&nums[i]>=nums[q.back()])
q.pop_back();
q.push_back(i);
while(q.front()<=i-k)
q.pop_front();
ans.push_back(nums[q.front()]);
}
return ans;
}
};
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n=nums.size();
priority_queue<pair<int,int>> q;
for(int i=0;i<k;i++){
q.emplace(nums[i],i);
}
vector<int> ans={q.top().first};
for(int i=k;i<n;i++){
q.emplace(nums[i],i);
while(q.top().second<=i-k)
q.pop();
ans.push_back(q.top().first);
}
return ans;
}
};
16.带限制的子序列和
题目来源:1425. 带限制的子序列和
题解:
class Solution {
public:
int constrainedSubsetSum(vector<int>& nums, int k) {
int n=nums.size();
vector<int> f(n);
f[0]=nums[0];
deque<int> dq;
dq.push_back(0);
int ans=nums[0];
for(int i=1;i<n;i++){
while(!dq.empty()&&i-dq.front()>k)
dq.pop_front();
f[i]=max(f[dq.front()],0)+nums[i];
ans=max(ans,f[i]);
while(!dq.empty()&&f[i]>f[dq.back()])
dq.pop_back();
dq.push_back(i);
}
return ans;
}
};
----------------------------------------------二叉堆-------------------------------------------------------
17.二叉树最大宽度
题目来源:662. 二叉树最大宽度
题解:
/**
* 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 {
public:
int widthOfBinaryTree(TreeNode* root) {
int width = 0;
queue<pair<TreeNode*, int>> q;
q.push({root, 0});
while(!q.empty()) {
long long start = q.front().second;
long long n = q.size();
long long index = start;
for(long long i = 0; i < n; i ++) {
TreeNode* node = q.front().first;
index = q.front().second;
if(node->left != nullptr) q.push({node->left, index * 2 - start});
if(node->right != nullptr) q.push({node->right, index * 2 - start + 1});
q.pop();
}
width = max(width, (int)(index - start + 1));
}
return width;
}
};
18.合并排序链表
题目来源:剑指 Offer II 078. 合并排序链表
题解:
/**
* 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 {
public:
int widthOfBinaryTree(TreeNode* root) {
int width = 0;
queue<pair<TreeNode*, int>> q;
q.push({root, 0});
while(!q.empty()) {
long long start = q.front().second;
long long n = q.size();
long long index = start;
for(long long i = 0; i < n; i ++) {
TreeNode* node = q.front().first;
index = q.front().second;
if(node->left != nullptr) q.push({node->left, index * 2 - start});
if(node->right != nullptr) q.push({node->right, index * 2 - start + 1});
q.pop();
}
width = max(width, (int)(index - start + 1));
}
return width;
}
};
19.根据字符出现频率排序
题目来源:451. 根据字符出现频率排序
题解:
class Solution {
public:
struct comp
{
bool operator()(pair<char,int> &a,pair<char,int> &b)
{
return a.second < b.second;
}
};
string frequencySort(string s) {
unordered_map<char,int> map;
int n=s.length();
for(int i=0;i<n;i++)
map[s[i]]++;
priority_queue<pair<char,int>,vector<pair<char,int>>,comp> q;
for(auto& [c,cnt]:map){
q.emplace(c,cnt);
}
string ans;
while(!q.empty()){
auto [c,cnt]=q.top();
q.pop();
for(int i=0;i<cnt;i++)
ans+=string(1,c);
}
return ans;
}
};
//官方题解:
class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> mp;
int length = s.length();
for (auto &ch : s) {
mp[ch]++;
}
vector<pair<char, int>> vec;
for (auto &it : mp) {
vec.emplace_back(it);
}
sort(vec.begin(), vec.end(), [](const pair<char, int> &a, const pair<char, int> &b) {
return a.second > b.second;
});
string ret;
for (auto &[ch, num] : vec) {
for (int i = 0; i < num; i++) {
ret.push_back(ch);
}
}
return ret;
}
};
20.设计推特
题目来源:355.设计推特
题解:
//面向对象,设计两个struct:推文和用户
int global_Time=0;
class Tweet{
public:
int id;
int time;
Tweet* next;
Tweet(int id){
this->id=id;
this->time=global_Time++;
next=nullptr;
}
};
class User{
public:
int id;
Tweet *tweet;
unordered_set<int> follows;
User(int id){
this->id=id;
tweet=nullptr;
}
void follow(int followeeId){
if(followeeId==id) return;
follows.insert(followeeId);
}
void unfollow(int followeeId){
if(!follows.count(followeeId)||followeeId==id) return;
follows.erase(followeeId);
}
void post(int tweetId){
Tweet *newtweet=new Tweet(tweetId);
newtweet->next=tweet;
tweet=newtweet;
}
};
class Twitter {
public:
struct cmp{
bool operator()(Tweet *a,Tweet *b){
return a->time<b->time;
}
};
unordered_map<int,User*> user_map;
Twitter() {
user_map.clear();
}
void postTweet(int userId, int tweetId) {
if(user_map.find(userId)==user_map.end()){
user_map[userId]=new User(userId);
}
user_map[userId]->post(tweetId);
}
vector<int> getNewsFeed(int userId) {
if(user_map.find(userId)==user_map.end()) return {};
priority_queue<Tweet*,vector<Tweet*>,cmp> q;
if(user_map[userId]->tweet)
q.push(user_map[userId]->tweet);
for(int followeeId:user_map[userId]->follows)
{
if(user_map.find(followeeId)==user_map.end()) continue;
Tweet *head=user_map[followeeId]->tweet;
if(head==nullptr) continue;
q.push(head);
}
vector<int> res;
while(!q.empty()){
Tweet *t=q.top();
q.pop();
res.push_back(t->id);
if(res.size()==10) return res;
if(t->next)
q.push(t->next);
}
return res;
}
void follow(int followerId, int followeeId) {
if(user_map.find(followerId)==user_map.end())
user_map[followerId]=new User(followerId);
if(user_map.find(followeeId)==user_map.end())
user_map[followeeId]=new User(followeeId);
user_map[followerId]->follow(followeeId);
}
void unfollow(int followerId, int followeeId) {
if(user_map.find(followerId)==user_map.end())
user_map[followerId]=new User(followerId);
user_map[followerId]->unfollow(followeeId);
}
};
/**
* Your Twitter object will be instantiated and called as such:
* Twitter* obj = new Twitter();
* obj->postTweet(userId,tweetId);
* vector<int> param_2 = obj->getNewsFeed(userId);
* obj->follow(followerId,followeeId);
* obj->unfollow(followerId,followeeId);
*/