代码随想录算法训练营day11 | 150.逆波兰表达式求值、239.滑动窗口最大值、347.前K个高频元素

150.逆波兰表达式求值
栈的应用:后缀表达式求值

点击查看代码
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> stk;
        for(int i = 0; i < tokens.size(); ++i) {
            if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
                int ropnum = stk.top();
                stk.pop();
                int lopnum = stk.top();
                stk.pop();
                if(tokens[i] == "+") stk.push(lopnum + ropnum);
                else if(tokens[i] == "-") stk.push(lopnum - ropnum);
                else if(tokens[i] == "*") stk.push(lopnum * ropnum);
                else stk.push(lopnum / ropnum);
            }
            else {
                int weight = 1;
                int sum = 0;
                //将表示数字的字符串转为真正的数字int,存在sum中,再压栈
                for(int j = tokens[i].size() - 1; j >= 0; --j) {
                    //注意有可能遇到负数的情况
                    if(j == 0 && tokens[i][j] == '-') sum *= -1;
                    else {
                        sum += (tokens[i][j] - '0') * weight;
                        weight *= 10;
                    }
                    
                }
                stk.push(sum);
            }
        }
        return stk.top();
    }
};

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:
1、去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
2、适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。

239.滑动窗口最大值
解法一:暴力解法(结果超时)

点击查看代码
class Solution {
public:
    int maxValue(vector<int> &nums, int left, int right) {
        int maxval = nums[left];
        for(int i = left + 1; i <= right; ++i) maxval = max(maxval, nums[i]);
        return maxval;
    }

    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int left = 0;
        int right = left + k - 1;
        vector<int> result;
        while(right <= nums.size() - 1) {
            result.push_back(maxValue(nums, left, right));
            ++left;
            ++right;
        }
        return result;
    }
};

解法二:使用单调队列(难)

点击查看代码
class Solution {
private:
    //实现单调队列,队头元素为当前窗口内的最大值,队内元素由大到小排列,仅保留有可能成为最大值的元素
    class MyQueue {
    private:
        deque<int> dque;

    public:    
        
        //小于等于待push元素x的元素,由于较小且比起x来说会更早滑出窗口,故后续不可能成为最大值,可直接pop
        //x需要插入到第一个比x大的值后面,等待前面的值均滑出窗口后,x就可以成为新的窗口内最大值,并且,排在
        //后面的元素必然是后入队的,必然会更晚滑出窗口
        void push(int x) { //x为即将滑入窗口的值
            //注意此处< x不能写成<= x,相同的值需要随着窗口滑动轮流成为最大值,并且随着pop自行淘汰
            //若写成<= x,该用例会报错[-7,-8,7,5,7,1,6,0] 
            //预期为[7,7,7,7,7] 结果错误为[7,7,7,6,6]
           while(!dque.empty() && dque.back() < x) dque.pop_back();
           dque.push_back(x); 
        }

        //x要么小于队头元素,要么等于,不可能大于,因为队头元素就是当前窗口最大值
        //若x等于队头元素,即当前窗口最大值,直接弹出,x后面的元素成为新的窗口最大值,
        //不用担心x之后元素不在新的窗口内,因为x后的元素必然是后入队的,必然会更晚滑出窗口
        void pop(int x) { //x为即将滑出窗口的值
            if(x == dque.front()) dque.pop_front();
        }

        int front() {
            return dque.front();
        }

    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue myque;
        for(int i = 0; i < k; ++i) {
            myque.push(nums[i]);
        }
        vector<int> result;
        for(int i = k; i < nums.size(); ++i) {
            result.push_back(myque.front());
            myque.pop(nums[i-k]);
            myque.push(nums[i]);
        }
        result.push_back(myque.front());
        return result;
    }
};

347.前K个高频元素(难)
使用优先级队列priority_queue,即大/小顶堆,队头元素即为堆顶元素

点击查看代码
class Solution {
public:
    //自定义比较规则,用于传入priority_queue
    class myCompare {
    public:
        bool operator()(const pair<int, int> &left, const pair<int, int> &right) {
            //相当于队头在右边,右边小,则为小顶堆
            return left.second > right.second;
        }           
    };

    vector<int> topKFrequent(vector<int>& nums, int k) {
        
        //利用map统计每个元素的频率
        unordered_map<int, int> uomap;
        for(int i = 0; i < nums.size(); ++i)
            ++uomap[nums[i]];

        //构建小顶堆,对map里的元素进行排序
        //堆中元素类型  底层容器类型  排序规则
        priority_queue<pair<int, int>, vector<pair<int, int>>, myCompare> pri_que;

        for(auto iter = uomap.begin(); iter != uomap.end(); ++iter) {
            pri_que.push(*iter);
            if(pri_que.size() > k)
                pri_que.pop(); //让堆始终保持k个最大的
        }

        //将筛选后的堆中元素的first域逐个放入用于返回的vector中
        vector<int> result(k);
        for(int i = k - 1; i >= 0; --i) {
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};

2025/02/23

posted @   coder小杰  阅读(0)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示