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_queueclass 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