表达式求值 算术表达式的形式 前缀表达式 :<操作符> <操作数> <操作数>
中缀表达式 :<操作数> <操作符> <操作数>
后缀表达式 :<操作数> <操作数> <操作符>
后缀表达式不需要括号和运算符优先级
中缀表达式转后缀表达式 遍历中缀表达式 各个字符
准备一个后缀表达式的答案 和辅助栈
对每个运算符设定一个栈外优先级和站内优先级,从左到右结合的运算符这两个相同,从右到左结合的运算符栈外比站内大
最终再把辅助栈中所有操作符加入后缀表达式 中
后缀表达式的计算 遍历后缀表达式 各个字符
准备一个辅助栈
为操作数:直接入栈 为操作符:连续出栈两次,先出栈 ,再出栈 计算操 作 符 把结果入栈 最后栈中数据即结果
例题
P1175 表达式的转换 - 洛谷
点击查看代码1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #include <iostream> #include <stack> #include <unordered_map> #include <cmath> using namespace std;unordered_map<char , pair<int , int >> priority = { {'+' , {1 , 1 }}, {'-' , {1 , 1 }}, {'*' , {2 , 2 }}, {'/' , {2 , 2 }}, {'^' , {4 , 3 }} }; void prints (string &s, int begin = 0 ) { for (int i = begin; i < s.size (); ++i) { cout << s[i] << ' ' ; } } int main () { string s, ans; cin >> s; stack<char > st; for (char c : s) { if (isdigit (c)) { ans.push_back (c); } else if (c == '(' ) st.push (c); else if (c == ')' ) { while (!st.empty () && st.top () != '(' ) { ans.push_back (st.top ()); st.pop (); } if (!st.empty ()) st.pop (); } else { while (!st.empty () && st.top () != '(' ) { char top = st.top (); if (priority[top].second >= priority[c].first) { ans.push_back (top); st.pop (); } else { break ; } } st.push (c); } } while (!st.empty ()) { ans.push_back (st.top ()); st.pop (); } prints (ans); cout << endl; stack<int > st2; for (int i = 0 ; i < ans.size (); i++) { char c = ans[i]; if (isdigit (c)) { st2. push (c - '0' ); } else { int a = st2. top (); st2. pop (); int b = st2. top (); st2. pop (); int res; if (c == '+' ) res = b + a; else if (c == '-' ) res = b - a; else if (c == '*' ) res = b * a; else if (c == '/' ) res = b / a; else if (c == '^' ) res = pow (b, a); st2. push (res); stack<int > temp; while (!st2. empty ()) { temp.push (st2. top ()); st2. pop (); } while (!temp.empty ()) { cout << temp.top () << ' ' ; st2. push (temp.top ()); temp.pop (); } prints (ans, i + 1 ); cout << endl; } } return 0 ; }
相互实现 两个栈实现队列 232. 用栈实现队列 - 力扣(LeetCode)
一个栈保持弹入元素,另一个栈保持弹出元素
点击查看代码1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class MyQueue { stack<int > *s1, *s2; public : MyQueue () { s1 = new stack <int >(); s2 = new stack <int >(); } void push (int x) { s1->push (x); } int pop () { peek (); int res = s2->top (); s2->pop (); return res; } int peek () { if (s2->empty ()) { while (!s1->empty ()) { s2->push (s1->top ()); s1->pop (); } } return s2->top (); } bool empty () { return s1->empty () && s2->empty (); } };
一个队列实现栈 225. 用队列实现栈 - 力扣(LeetCode)
用一个记录栈顶元素,弹出时到栈顶元素之前让队列弹出的元素重新回到队列中,用之前记录栈顶元素的变量当作 这样能够记录弹出后的下一个栈顶元素
点击查看代码1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class MyStack { queue<int > *q; int tops = 0 ; public : MyStack () { q = new queue <int >(); } void push (int x) { q->push (x); tops = x; } int pop () { int size = q->size (); for (int i = 0 ; i < size - 1 ; i++) { tops = q->front (); q->pop (); q->push (tops); } int res = q->front (); q->pop (); return res; } int top () { return tops; } bool empty () { return q->empty (); } };
单调栈 用栈实现了一组单调递增/递减的值,即栈中元素具有单调性
一般存角标,也可能存值,存角标能解决存值不能解决的问题
左侧/右侧第一个比更大/更小的元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 vector<int > nextGreaterElement (vector<int >& nums) { stack<int > s; vector<int > result (nums.size(), -1 ) ; for (int i = nums.size () - 1 ; i >= 0 ; --i) { while (!s.empty () && s.top () <= nums[i]) { s.pop (); } if (!s.empty ()) { result[i] = s.top (); } s.push (nums[i]); } return result; }
503. 下一个更大元素 II - 力扣(LeetCode)
改成循环数组
点击查看代码1 2 3 4 5 6 7 8 9 10 11 12 13 14 int n = nums.size ();vector<int > result (n, -1 ) ;stack<int > s; for (int i = 2 * n - 1 ; i >= 0 ; --i) { int cur = nums[i % n]; while (!s.empty () && s.top () <= cur) { s.pop (); } if (i < n && !s.empty ()) { result[i] = s.top (); } s.push (cur); } return result;
2454. 下一个更大元素 IV - 力扣(LeetCode)
用两个单调栈即可
点击查看代码1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 vector<int > nextGreaterElement (vector<int >& nums) { int n = nums.size (); vector<int > ans (n, -1 ) ; vector<int > s1; vector<int > s2; for (int i = 0 ; i < n; ++i) { while (!s2. empty () && nums[s2. back ()] < nums[i]) { ans[s2. back ()] = nums[i]; s2. pop_back (); } vector<int > tmp; while (!s1. empty () && nums[s1. back ()] < nums[i]) { tmp.push_back (s1. back ()); s1. pop_back (); } while (!tmp.empty ()) { s2. push_back (tmp.back ()); tmp.pop_back (); } s1. push_back (i); } return ans; }
接雨水 42. 接雨水 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int trap (vector<int > &height) { stack<int > s; int cnt = 0 ; for (int i = 0 ; i < height.size (); ++i) { while (!s.empty () && height[s.top ()] < height[i]) { int low = height[s.top ()]; s.pop (); if (s.empty ()) break ; int high = min (height[s.top ()], height[i]); cnt += (i - s.top ()- 1 ) * (high - low); } s.push (i); } return cnt; }
左侧最远的比其大的元素 维护一个单调递增的栈
每次在栈上二分得到最远的比其大的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 vector<int > leftMostFarGreaterElement (vector<int >& nums) { int n = nums.size (); vector<int > ans (n, -1 ) ; vector<int > s; for (int i = 1 ; i <= n; ++i) { if (s.empty () || nums[i] < nums[s.back ()]) { s.push_back (i); } else { int l = 1 , r = s.size (), ansId = 0 ; while (l <= r) { int mid = (l + r) >> 1 ; if (nums[s[mid]] > nums[i]) ansId = mid, r = mid - 1 ; else l = mid + 1 ; } ans[i] = s[ansId]; } } return ans; }
单调队列 用队列实现了一组单调递增/递减的值,即队列中元素具有单调性
一般存角标
滑动窗口最大值 239. 滑动窗口最大值 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 vector<int > maxSlidingWindow (vector<int >& nums, int k) { deque<int > q; vector<int > ans; int n = nums.size (); for (int i = 0 ; i < n; i++) { if (!q.empty () && q.back () == i-k) { q.pop_back (); } while (!q.empty () && nums[q.front ()] <= nums[i]) { q.pop_front (); } q.push_front (i); if (i >= k - 1 ) { ans.push_back (nums[q.back ()]); } } return ans; }
对动态规划的优化 单调队列优化 dp - 洛谷专栏