- C++中stack 是容器么? 栈,队列往往不被归类为容器,而被归类为container adapter(容器适配器)。因为由底层的容器实现,同时使用适配器模式的设计模式,封装了一层。
- 我们使用的stack是属于哪个版本的STL?SGI STL(linux C++使用的gcc)
- 我们使用的STL中stack是如何实现的?可以选择容器来实现栈的功能,vector,deque,list 都可以。默认是以deque为缺省情况下栈的底层结构(双向队列,封住一段,只开通另一端)。queue也是。
- stack ,queue提供迭代器来遍历stack空间么?不提供
1. LeetCode 232. 用栈实现队列 20231020
一遍过的一题,主要就是模拟一个输入栈,一个输出栈,只有要输出,或者要看顶部的时候才将输入栈里的东西倒到输出栈;还有就是函数名叫empty(),不叫isempty()。还有就是要熟悉栈的操作。还有,写top和pop的时候,top的代码可以复用,不要直接复制过来。
2. LeetCode 225. 用队列实现栈 20231020
也是一遍过的题,但是要熟悉队列的操作,比如queue.front(),queue.back().
我自己写的代码用到了3个queue,而下面的代码仅仅用到了一个queue,且只有一个函数是真正需要做事的,值得学习。
class MyStack { public:queue<int> que;/** Initialize your data structure here. */MyStack() {}/** Push element x onto stack. */void push(int x) {que.push(x);}/** Removes the element on top of the stack and returns that element. */int pop() {int size = que.size();size--;while (size--) { // 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部que.push(que.front());que.pop();}int result = que.front(); // 此时弹出的元素顺序就是栈的顺序了que.pop();return result;}/** Get the top element. */int top() {return que.back();}/** Returns whether the stack is empty. */bool empty() {return que.empty();} };
3.LeetCode 20. 有效的括号 20231020
今天连做三道简单题,这题卡的最久,久的原因居然是为了调试写了一个stk.top的打印,然后一直没看到这一行,导致疯狂报栈溢出的错。
这道题也是自己写出来,但是依旧很多需要注意的地方,主要是温习了map的键值对,unordered_map底层的哈希;unordered_map怎么往里面插入数据(insert,或者直接ump[x]=),怎么查找(find、ump[x]),其中还用到一个at(这又是怎么用),这里只用了insert和ump[x]
class Solution { public:bool isValid(string s) {stack<char> stk;unordered_map<char,char>ump;ump.insert({'[',']'});ump.insert({'(',')'});ump.insert({'{','}'});if (s.length()% 2 == 1) return 0;for (char i : s){if(stk.empty() || ump[stk.top()] != i)stk.push(i);elsestk.pop();}return stk.empty(); } };
看到别人一个解法,直接省去了我的ump,……
class Solution { public:bool isValid(string s) {if(s.size()%2) return false;stack<char> st;for(int i = 0; i < s.size(); ++i){if(s[i] == '(')st.push(')');else if(s[i] == '{')st.push('}');else if(s[i] == '[')st.push(']');else if(st.empty() || s[i] != st.top())return false;elsest.pop();}return st.empty();} };
4. LeetCode 1047. 删除字符串中的所有相邻重复项 20231023
又是一道栈的简单题,都没有别的写法,写完就是跟代码随想录一样的。但是依旧有更好的解法,拿字符串直接作为栈(当时写的时候就不想把字符串先变成栈再转换成字符串)。需要熟悉字符串的操作:.empty(),.back(),.pushback(),.pop_back()
5. LeetCode 150. 逆波兰表达式求值 20231023
先熟悉一个词:“向零截断”,其实也就是平时计算机处理数据的操作,2.3舍到2,-2.3也是舍到-2,即去掉小数部分。虽然做题没什么用~
看不起这道中等题,又是常规栈操作,没有什么算法上的难度。
里面要注意的就是
1.能合起来写的逻辑就别在if里面写四遍,这里只有num1+-*/num2这个句子要重写。
2.数据类型转换要注意。隐式转换、强制4种转换还不是很熟悉。有一个stoi,itos,stoll(string to longlong)要注意。这一题因为vector用的是string,导致switch用不了,强转char又难办。
3.要熟悉int,long,long long的数据长度。
6. LeetCode 239. 滑动窗口最大值 20231024
这是一道困难题,其实主要是思路第一次比较难想,我只知道像是用queue做的,但是不知道可以用deque来实现,并且插入删除有一套自己的规则。真正理解起来还是比较容易的。举个例子来看看:
这里,k=3,所以一开始队列
push:1,√ 队列:1
push:3,弹出1,√ 队列:3
push:-1,√(不因为前面有3就不进-1) 队列:3
然后往后移动:
pop:不pop1,因为早已经没了;push:-3 队列:3,-1,-3
pop:3,因为要push:5,所以还要pop:-1,-3 队列:5
pop:不pop-1,因为早已经没了;push:3 队列:5,3
pop:不pop-3,因为早已经没了;因为要push:6,所以还要pop:5,3 队列:6
pop:不pop5,因为早已经没了;因为要push:7,所以还要pop:6 队列:7
所以我们要实现的数据结构的三个操作是:
pop:每一次迭代去pop应该pop的位置上的数,都要pop还存在的数才行,这个就是直接用deque的pop_front
push:正常进,但是要pop掉前面比它小的数,所以要用到deque的pop_back
代码也不难,理解以后自己写出来了,其中需要自己定义一个类做新的数据结构。但是,仍然犯了几个小错误。
class MyQueue{ public:// pop:每一次迭代去pop应该pop的位置上的数,都要pop还存在的数才行,这个就是直接用deque的pop_frontvoid pop(int x){if(!dq.empty()&&x == dq.front())dq.pop_front(); }// push:正常进,但是要pop掉前面比它小的数,所以要用到deque的pop_backvoid push(int x){while(!dq.empty()&&dq.back() < x)//写成了!dq.empty()&&dq.front() < xdq.pop_back();//写成了dq.pop_front();dq.push_back(x);}int gettop(){return dq.front(); }deque<int> dq;};class Solution { public:MyQueue q;vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> v1; // 第一轮for(int i = 0; i < k; ++i){q.push(nums[i]);}v1.push_back(q.gettop());// 之后移动nums.length()-k次:for(int i = k; i < nums.size(); ++i){q.pop(nums[i - k]);// 错写成nums[i - k - 1]q.push(nums[i]);v1.push_back(q.gettop());}return v1;} };