- 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;
}
};