【2023/3/23-4/1】归并排序+LRU缓存+字典树/前缀树

学习链接:

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.键值映射
题解:

  1. 暴力穷举
  2. 前缀和
  3. 字典树
//暴力穷举法
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. 环形子数组的最大和
题解:

  1. 网络解法
  2. 单调队列
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();

题解:

  1. 双向队列
  2. 优先队列
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);
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值