- 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); else stk.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; else st.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_front void pop(int x){ if(!dq.empty()&&x == dq.front()) dq.pop_front(); } // push:正常进,但是要pop掉前面比它小的数,所以要用到deque的pop_back void push(int x){ while(!dq.empty()&&dq.back() < x)//写成了!dq.empty()&&dq.front() < x dq.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; } };