1. 225. 用队列实现栈
用一个队列就可以实现栈
取元素时要把队列尾元素取出(最后进入队列的元素)
把前n-1个元素放到队列尾并弹出,这样队列的头部就是最后进入队列的元素了,取出他即可
class MyStack {
private:
queue<int> que;
public:
MyStack() {
}
void push(int x) {
que.push(x);
}
int pop() {
int n = que.size() - 1;
while(n--){
que.push(que.front());
que.pop();
}
int res = que.front();
que.pop();
return res;
}
int top() {
return que.back();
}
bool empty() {
return que.empty();
}
};
2. 面试题 03.04. 化栈为队
需要把栈最里面的元素取出来,不能像队列那样操作了,那样最里面的元素依旧在最里面
用两个栈,把1栈所有元素取出放到2栈中,此时2栈中所有元素出栈顺序为队列顺序,直接取出元素即可
注意只有当栈2位空时才补充元素到栈2,否则会影响出栈顺序
class MyQueue {
private:
stack<int> stk1;
stack<int> stk2;
public:
MyQueue() {
}
void push(int x) {
stk1.push(x);
}
int pop() {
if(stk2.empty()){
while(!stk1.empty()){
stk2.push(stk1.top());
stk1.pop();
}
}
int res = stk2.top();
stk2.pop();
return res;
}
int peek() {
if(stk2.empty()){
while(!stk1.empty()){
stk2.push(stk1.top());
stk1.pop();
}
}
return stk2.top();
}
bool empty() {
return stk1.empty() && stk2.empty();
}
};
3. 1021. 删除最外层的括号
方法一:
相当于单调栈,栈中只放左括号,遇到右括号弹出一个左括号,用是否栈空判断括号是否完全
要在添加之前,删除之后,判断站是否为空,来判断是否为中间元素
string removeOuterParentheses(string S) {
stack<char> stk;
int start = 0;
string res = "";
for(int i = 0; i < S.size(); i++){
if(S[i] == ')'){
stk.pop();
}
if(!stk.empty()){
res += S[i];
}
if(S[i] == '('){
stk.push('(');
}
}
return res;
}
方法二:
原理相同,改用变量记录左括号个数,节省空间
string removeOuterParentheses(string S) {
stack<char> stk;
int count = 0;
string res = "";
for(int i = 0; i < S.size(); i++){
if(S[i] == ')'){
count--;
}
if(count != 0){
res += S[i];
}
if(S[i] == '('){
count++;
}
}
return res;
}
4. 1047. 删除字符串中的所有相邻重复项
模拟栈节省空间,原地修改,指针指向当前最后一个元素,与前一个元素不相同就加入,相同就退格(删除),最后重新设定字符串大小
也可以新建立一个字符串,用push_back(),pop_back()模拟栈
string removeDuplicates(string S) {
int index = 0;
for(char c : S){
if(index == 0 || S[index - 1] != c){
S[index++] = c;
}
else{
index--;
}
}
S.resize(index);
return S;
}
5. 155. 最小栈
-1,1,1 当-1不退栈时,最小值永远是-1
方法一:
用辅助栈,辅助栈顶存放当前最小值,辅助栈与栈同时退栈
如-1,-1,-2,1辅助栈存放为,-1,-1,-2,-2
入栈时当前值小于辅助栈顶时更换元素
也可以用stack<int,pair<int,int>> 类型
class MinStack {
private:
stack<int> stk_min;
stack<int> stk;
public:
void push(int x) {
if(stk.empty()){
stk_min.push(x);
}
else{
stk_min.push(min(x,stk_min.top()));
}
stk.push(x);
}
void pop() {
stk_min.pop();
stk.pop();
}
int top() {
return stk.top();
}
int getMin() {
return stk_min.top();
}
};
方法二:
只用一个栈,栈中储存与最小值的差值,min储存当前最小值
要用long储存,栈中元素最大为INT_MAX - INT_MIN
top,元素为负数时,返回当前最小值(此时差值用于计算出上一个min),为负数时当前min就是他的值
push、pop,当元素为负数时更换最小值
class MinStack {
private:
stack<long> stk;
long min;
public:
void push(int x) {
if(stk.empty()){
min = x;
}
stk.push(x - min);
if(x < min){
min = x;
}
}
void pop() {
if(stk.top() < 0){
min -= stk.top();
}
stk.pop();
}
int top() {
if(stk.top() < 0) return min;
return min + stk.top();
}
int getMin() {
return min;
}
};
6. 1019. 链表中的下一个更大节点
单调栈:用于找数组中第一个比他大的数据(单调递减栈,留在栈中的都是后来没有比他的数了)
栈中存放的是索引,因为只知道数据大小是没办法准确插入到相应位置的
vector<int> nextLargerNodes(ListNode* head) {
stack<int> stk;
int n = 0;
vector<int> nums;
while(head != nullptr){
nums.push_back(head->val);
head = head->next;
n++;
}
vector<int> res(n,0);
for(int i = 0; i < nums.size(); i++){
while(!stk.empty() && nums[stk.top()] < nums[i]){
res[stk.top()] = nums[i];
stk.pop();
}
stk.push(i);
}
return res;
}
本题优化,用res数组兼职nums和res数组的功能,因为只使用之前的数据且res数据记录答案后就不再使用了,所以边记录边比较同时可以直接覆盖
由于默认值没有设置,所以再遍历一遍栈,将栈中剩余元素置为0(剩余元素都是右边没有更大值了,即递减的)
vector<int> nextLargerNodes(ListNode* head) {
stack<int> stk;
int i = 0;
vector<int> res;
while(head != nullptr){
while(!stk.empty() && res[stk.top()] < head->val){
res[stk.top()] = head->val;
stk.pop();
}
res.push_back(head->val);
stk.push(i++);
head = head->next;
}
while(!stk.empty()){
res[stk.top()] = 0;
stk.pop();
}
return res;
}
收获与体会
- 一般可以用模拟栈的方式节省空间
- 找第一个比当前元素大/小的数就用单调栈做