栈和队列
栈的基本操作
empty() 堆栈为空则返回真
pop() 移除栈顶元素 (删除)
push() 在栈顶增加元素 (增加)
size() 返回栈中元素数目
top() 返回栈顶元素,不删除(获取)
队列的基本操作
back()返回最后一个元素
empty()如果队列空则返回真
front()返回第一个元素
pop()删除第一个元素
push()在末尾加入一个元素
size()返回队列中元素的个数
232. 用栈实现队列 - 力扣(LeetCode) (leetcode-cn.com)
注意细节,要等输出栈空了才能转移输入栈元素到输出栈,否则先push1234,再pop一次,输出还剩下234,再push5,这时候如果直接放入输出栈,会直接放在头部,首先输出,再依次输出的话就是5234了
1 class MyQueue { 2 public: 3 stack<int> stIn; 4 stack<int> stOut; 5 MyQueue() { 6 7 } 8 9 void push(int x) {//push和pop交替,那么这种情况,必须stOut为空了,再转移stIn里的数据 10 stIn.push(x); 11 } 12 13 int pop() { 14 15 int res = this->peek(); 16 stOut.pop(); 17 return res; 18 } 19 20 int peek() { 21 if(stOut.empty()) 22 while(!stIn.empty()){ 23 stOut.push(stIn.top()); 24 stIn.pop(); 25 } 26 int res = stOut.top(); 27 return res; 28 } 29 30 bool empty() { 31 return stIn.empty()&&stOut.empty(); 32 } 33 };
225. 用队列实现栈 - 力扣(LeetCode) (leetcode-cn.com)
class MyStack { public: queue<int> que; MyStack() { } void push(int x) { que.push(x); } int pop() { int res = que.back(); int size = que.size(); size--; while(size--){ que.push(que.front()); que.pop(); } que.pop(); return res; } int top() { return que.back(); } bool empty() { return que.empty(); } };
20. 有效的括号 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool isValid(string s) { 4 stack<char> st; 5 for(int i=0;i<s.size();i++){ 6 if(s[i]=='('||s[i]=='{'||s[i]=='[') 7 st.push(s[i]); 8 else{ 9 if(st.empty())//")))" 10 return false; 11 char temp = st.top(); 12 st.pop(); 13 cout<<s[i]<<temp; 14 if((temp=='('&&s[i]==')')||(temp=='{'&&s[i]=='}')||(temp=='['&&s[i]==']'))//三种正确情况,就继续执行 15 continue; 16 else 17 return false; 18 } 19 } 20 if(st.empty()) 21 return true; 22 else 23 return false; 24 } 25 };
另外一种巧写法,比如碰到左括号就放入对应右括号哈哈哈,这样就可以直接判等了
1 class Solution { 2 public: 3 bool isValid(string s) { 4 stack<char> st; 5 for(int i=0;i<s.size();i++){ 6 if(s[i]=='(') 7 st.push(')'); 8 else if(s[i]=='{') 9 st.push('}'); 10 else if(s[i]=='[') 11 st.push(']'); 12 else if(st.empty()||st.top()!=s[i]) 13 return false; 14 else 15 st.pop(); 16 } 17 return st.empty(); 18 } 19 };
150. 逆波兰表达式求值 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int evalRPN(vector<string>& tokens) { 4 stack<int> st; 5 for(int i=0;i<tokens.size();i++){ 6 if(tokens[i]=="+"|tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/"){//碰到运算符就弹两个数出来操作,操作完压栈,碰到数字压栈 7 int a = st.top();st.pop();//注意a,b顺序,a先出是靠后的数,b在a前 8 int b = st.top();st.pop(); 9 if(tokens[i]=="+") 10 st.push(b+a); 11 else if(tokens[i]=="-") 12 st.push(b-a); 13 else if(tokens[i]=="*") 14 st.push(b*a); 15 else if(tokens[i]=="/") 16 st.push(b/a); 17 }else{ 18 19 st.push(stoi(tokens[i])); 20 } 21 } 22 return st.top(); 23 } 24 };
滑动窗口k,维护的队列长度其实是<=k的,因为队列进行了数据筛选,如果数组下标大的还比下标小的数据大,那么下标小的数在队列(滑动窗口)里就没有存在的必要了,基于这种情况做出的单调性
比如 1,3,-1,-3,5,3,6,7,k=3
初始化队列:3,-1
i=3:3,-1,-3
i=4:5
i=5:5,3
i=6:6
i=7:7
懂了吧哈哈哈
239. 滑动窗口最大值 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 private: 3 class MyQueue{ 4 public: 5 deque<int> que; 6 void pop(int value){ 7 if(!que.empty()&&value == que.front())//value和front大小关系,value不可能闭front大, 8 //如果比front小,那么队列里没有value这个值了,因为递增,value早在front加入队列时push操作那就被移除了,这时候就不用移除了 9 que.pop_front(); 10 11 } 12 void push(int value){ 13 while(!que.empty()&&value>que.back()){//比它后放入队列,也就是在队列靠后位置还比队列前面的数大,那就前面的数没有存在的必要了 14 que.pop_back(); 15 } 16 que.push_back(value); 17 } 18 int front(){ 19 return que.front(); 20 } 21 }; 22 public: 23 vector<int> maxSlidingWindow(vector<int>& nums, int k) { 24 MyQueue que; 25 vector<int> result; 26 for(int i=0;i<k;i++){ 27 que.push(nums[i]); 28 } 29 result.push_back(que.front());//这里要先放入一次结果 30 for(int i=k;i<nums.size();i++){ 31 que.pop(nums[i-k]); 32 que.push(nums[i]); 33 result.push_back(que.front()); 34 } 35 return result; 36 } 37 };
自定义重载优先队列,第一种pair实现,第一种结构体,最后一种就是契合默认优先队列,按第一位排序且是大根堆,队首最大
自定义vector,第四种,时间慢了,维护了n个元素,nlog(n),队列的话只维护k个元素,就是nlog(k)
347. 前 K 个高频元素 - 力扣(LeetCode) (leetcode-cn.com)
这个题也可以不用重载,放入优先队列时,交换一下first和second的位置,因为是根据second来排序,所以把second排在第一位,然后有因为默认是大根堆每次弹出最大的,取相反数就刚好了。还要注意结果数据和队列一次弹出数据是反着的。
如果是设置成友元函数(friend),一定要注意:
(1)当重载友元函数时,将没有隐含的参数this指针。这样,对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。
(2)有些运行符不能重载为友元函数,它们是:=,(),[]和->。
比如这道题结构体重载<,就要用friend消除this指针,不然报错三个参数啥的。
1 class Solution { 2 public: 3 typedef pair<int, int> PII; 4 struct cmp{ 5 bool operator ()(const PII& l,const PII& r){ 6 return l.second>r.second; 7 } 8 }; 9 10 vector<int> topKFrequent(vector<int>& nums, int k) { 11 12 unordered_map<int, int> mp; 13 for(auto num: nums) mp[num] ++ ; 14 priority_queue<PII,vector<PII>,cmp> pq; 15 for(auto item: mp){ 16 pq.push(item); 17 if(pq.size() > k) pq.pop(); 18 } 19 vector<int> res(k); 20 for(int i = k - 1; i >= 0; i --){ 21 res[i] = pq.top().first; 22 pq.pop(); 23 } 24 return res; 25 } 26 };
1 class Solution { 2 public: 3 struct node{ 4 int x, y; 5 friend bool operator < (node a, node b){ 6 return a.y > b.y; //y小的优先 7 } 8 }; 9 10 vector<int> topKFrequent(vector<int>& nums, int k) { 11 unordered_map<int, int> mp; 12 for(auto num: nums) mp[num] ++ ; 13 priority_queue<node> pq; 14 for(auto item: mp){ 15 node t; 16 t.x = item.first; 17 t.y = item.second; 18 pq.push(t); 19 if(pq.size() > k) pq.pop(); 20 } 21 vector<int> res(k); 22 for(int i = k - 1; i >= 0; i --){ 23 res[i] = pq.top().x; 24 pq.pop(); 25 } 26 return res; 27 } 28 };
1 class Solution { 2 public: 3 vector<int> topKFrequent(vector<int>& nums, int k) { 4 typedef pair<int, int> PII; 5 unordered_map<int, int> mp; 6 for(auto num: nums) mp[num] ++ ; 7 priority_queue<PII> pq; 8 for(auto item: mp){ 9 PII t(-item.second, item.first); 10 pq.push(t); 11 if(pq.size() > k) pq.pop(); 12 } 13 vector<int> res(k); 14 for(int i = k - 1; i >= 0; i --){ 15 res[i] = pq.top().second; 16 pq.pop(); 17 } 18 return res; 19 } 20 };
1 class Solution { 2 public: 3 struct node{ 4 int x, y; 5 friend bool operator < (node a, node b){ 6 return a.y > b.y; //y小的优先 7 } 8 }; 9 10 vector<int> topKFrequent(vector<int>& nums, int k) { 11 unordered_map<int, int> mp; 12 for(auto num: nums) mp[num] ++ ; 13 vector<node> pq; 14 for(auto item: mp){ 15 node t; 16 t.x = item.first; 17 t.y = item.second; 18 pq.push_back(t); 19 } 20 sort(pq.begin(),pq.end()); 21 vector<int> res(k); 22 for(int i = 0; i < k; i ++){ 23 res[i] = pq[i].x; 24 } 25 return res; 26 } 27 };
42. 接雨水 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution {//记录当前列最左边高度和最右边高度,取他们之间较小的那个,与当前列高度作差就是当前列的雨水 2 public://第一和最后不接水 3 int trap(vector<int>& height) {//化整为零,不要想着一次性求解每一步大块面积,一数列一数列随着i的遍历来。不要一会按行计算一会按列计算,稀里糊涂。一直按行计算也行。 4 int sum = 0; 5 vector<int>left(height.size(),height[0]);vector<int>right(height.size(),height[height.size()-1]); 6 for(int i=1;i<height.size()-1;i++){ 7 left[i] = max(left[i-1],height[i]); 8 } 9 for(int i=height.size()-2;i>=0;i--){ 10 right[i] = max(right[i+1],height[i]); 11 } 12 for(int i=1;i<height.size()-1;i++){ 13 sum+=max(0,min(left[i],right[i])-height[i]); 14 } 15 return sum; 16 17 } 18 };