代码随想录算法训练营第十一天 | 栈与队列 150. 逆波兰表达式求值 239. 滑动窗口最大值 347.前 K 个高频元素

150. 逆波兰表达式求值

        这题难点在于找到其中规律并进行模拟。有了思路后整体不难,另外这里得掌握stoi函数和to_string函数。

class Solution {
public:
    int calculate(int num1,int num2,const string& s) {
        if(s == "+") return num1 + num2;
        if(s == "-") return num1 - num2;
        if(s == "*") return num1 * num2;
        if(s == "/") return num1 / num2;//应该判断num2是否为0,这里测试能通过就不判断了
        return -1;
    }
    int evalRPN(vector<string>& tokens) {
        stack<int> stk;
        int num1, num2, res;
        for(auto ch:tokens) {
            if(ch=="+" || ch=="-" || ch=="*" || ch=="/") {
                num2 = stk.top();
                stk.pop();
                num1 = stk.top();
                stk.pop();   
                res = calculate(num1,num2,ch);    
                stk.push(res);         
            }else{
                stk.push(stoi(ch));    
            }
            
        }
        return stk.top();
    }
};

239. 滑动窗口最大值

        这题开始用的暴力求解法,但是时间复杂度为O(k*n)太高,看了解题思路后醍醐灌顶。滑动窗口可以等效为双向队列尾部插入(push_back)一个元素,队首弹出(pop)一个元素。deque是我们的理想数据结构,但它没法直接求出队列中的最大元素。所以这里要创建一个数据结构,要求是:1. push和pop的时间复杂度皆为O(1)。2. 保持队首元素永远最大。

        按照要求我们创建了Myque,提示:1. 后一个元素如果比前面的元素大,那么前面的元素一定要舍弃。2. 弹出左指针对应的元素,因为左指针右移,之前指向的元素超过了滑动窗口边界。

class Solution {
public:
    //创造一个数据结构,使队首元素永远最大
    struct Myque{
        deque<int> que;
        void push(int value){
            while(!que.empty() && value > que.back()){
                que.pop_back();
            }
            que.push_back(value);
        }
        void pop(int value){
            if(!que.empty() && que.front() == value) {
                que.pop_front();
            }
        }
        int top(){
            return que.front();
        }
    };
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        Myque que;
        vector<int> result;
        for(int i = 0; i < k; ++i) {
            que.push(nums[i]);
        }
        result.push_back(que.top());
        for(int i = k; i <nums.size(); ++i) {
            que.pop(nums[i-k]);
            que.push(nums[i]);
            result.push_back(que.top());
        }
        return result;
    }
};

347.前 K 个高频元素

        这题要结合unordered_map(统计出现次数)和priority_queue(对出现次数排序)。大堆顶(堆顶值最大,然后逐步减小)和小堆顶(堆顶值最小,然后逐步增大)很难记,每次用都得查一下它比较器的顺序。比较器返回true表示优先级较低,举例:

        下图比较器left.second > right.second返回true,表示左边元素优先级较低(即更大的值放在更低的位置),即是小顶堆。

        auto compare = [](pair<int,int> left, pair<int,int> right){
            return left.second > right.second;
        };
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        auto compare = [](pair<int,int> left, pair<int,int> right){
            return left.second > right.second;
        };
        unordered_map<int,int> umap;
        for(auto n:nums) {
            umap[n]++;
        }
        //小顶堆(堆顶到堆底元素逐渐变大)
        priority_queue<pair<int,int>, vector<pair<int,int>>,decltype(compare)> preQue;
        for(auto it = umap.begin();it!=umap.end();++it) {
            preQue.push(*it);
            if(preQue.size() > k) 
                preQue.pop();//弹出最小的元素
        }
        vector<int> res(k);
        for(int i = k-1; i >= 0; i--) {
            res[i] = preQue.top().first;
            preQue.pop();
        }
        return res;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值