栈和队列基础知识
栈和队列常用操作
stack:栈
头文件: # include < stack > 模拟栈的功能和特点: 元素后进先出, 只能访问栈顶元素, 属于C++特殊容器
1、构造函数
stack <int> st, st1;//定义 int 类型的栈
stack <char> stch;//定义 char 类型的栈
stack <string> ststr;//定义 string 类型的栈
stack <int> st2(st);// 定义新容器, 拷贝 st 所有的元素
stack <int, vector<int> > st3;//底层使用 vector 容器实现栈, 默认是 deque
2、成员函数
st.top();//返回栈顶元素
st.push(5);//在栈顶插入新元素 5
st.emplace(5);//在栈顶创建新元素 5
st.pop();//删除栈顶元素
st.size();//返回容器目前的元素个数
st.empty();//容器为空返回 true, 否则返回 false
st.swap(st1);//交换两个容器的内容
queue:队列
头文件: # include < queue > 模拟队列的功能和特点: 元素先进先出, 可以访问队列两端元素, 属于C++特殊容器
1、构造函数
queue <int> q, q1;//定义 int 类型的队列
queue <char> qch;//定义 char 类型的队列
queue <string> qstr;//定义 string 类型的队列
queue <int> q2(q);//定义新容器, 拷贝 q 所有的元素
queue <int, vector<int> > q3;//使用 vector 容器实现队列, 默认是 deque
2、成员函数
q.front();//返回队列头部元素
q.back();//返回队列尾部元素
q.push(5);//在队列尾部插入新元素 5
q.emplace(5);//在队列尾部创建新元素 5
q.pop();//删除队列头部元素
q.size();//返回容器目前的元素个数
q.empty();//容器为空返回 true, 否则返回 false
q.swap(q1);//交换两个容器的内容
题目:
232.用栈实现队列
题目链接:232.用栈实现队列
讲解视频:栈的基本操作! | LeetCode:232.用栈实现队列
题目描述:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
说明:
- 你 只能 使用标准的栈操作 —— 也就是只有
push to top
,peek/pop from top
,size
, 和is empty
操作是合法的。 - 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例 1:
输入: ["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 1, 1, false]
解题思路:
使用两个栈st1,st2。st1用于push操作,st2用于pop和peek操作,当用到pop和peek操作时要保证st1中所有元素都放入st2中。
代码:
class MyQueue {
public:
MyQueue() {
}
void push(int x) {
s1.push(x);
}
int pop() {
if(s2.empty())
while(!s1.empty()) s2.push(s1.top()),s1.pop();
int tp = s2.top();
s2.pop();
return tp;
}
int peek() {
if(s2.empty())
while(!s1.empty()) s2.push(s1.top()),s1.pop();
return s2.top();
}
bool empty() {
if(s1.empty() && s2.empty()) return true;
return false;
}
private:
stack<int> s1;
stack<int> s2;
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
225.用队列实现栈
题目链接:225.用队列实现栈
讲解视频:队列的基本操作! | LeetCode:225. 用队列实现栈
题目描述:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。
注意:
- 你只能使用队列的标准操作 —— 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。 - 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
示例:
输入: ["MyStack", "push", "push", "top", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 2, 2, false]
解题思路:
不能用第一题的思路,因为队列是先进先出机制。该题目使用一个队列即可模拟栈。
调用push操作时正常入队列;当调用pop/top操作时,将前n-1个数出队列并从重新从队尾入队,记录第n个数值,并对其进行出队列操作,如果是top则将第n个数再次从队尾入队,最后返回已记录的第n个数值。
代码:
class MyStack {
public:
MyStack() {
}
void push(int x) {
q1.push(x);
}
int pop() {
int len = q1.size();
len--;
while(len--)
{
int tp = q1.front();
q1.pop();
q1.push(tp);
}
int x = q1.front();
q1.pop();
return x;
}
int top() {
int len = q1.size();
len--;
while(len--)
{
int x = q1.front();
q1.pop();
q1.push(x);
}
int tp = q1.front();
q1.pop();
q1.push(tp);
return tp;
}
bool empty() {
if(q1.empty()) return true;
else return false;
}
private:
queue<int> q1;
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
20.有效的括号
题目链接:20.有效的括号
讲解视频:栈的拿手好戏!| LeetCode:20. 有效的括号
题目描述:
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()" 输出:true
示例 2:
输入:s = "(]" 输出:false
解题思路:
使用栈数据结构。有如下几个思考点:
- s长度为偶数时才有可能正确
- 左括号一定要在右括号前入栈--um[tp]< um[c]
- 已结束后栈是否为空作为判断标准
代码:
class Solution {
public:
bool isValid(string s) {
if (s.size() % 2 != 0) return false; // 如果s的长度为奇数,一定不符合要求
stack<char> st;
unordered_map<char,int> um;
um['('] = -1, um[')'] = 1;
um['['] = -2, um[']'] = 2;
um['{'] = -3, um['}'] = 3;
for(auto c : s)
{
if(st.empty()) st.push(c);
else
{
char tp = st.top();
if(um[tp] < um[c] && um[tp] * (-1) == um[c]) st.pop();
else st.push(c);
}
}
if(st.empty()) return true;
return false;
}
};
1047.删除字符串中的所有
题目链接:1047.删除字符串中的所有
讲解视频:栈的好戏还要继续!| LeetCode:1047. 删除字符串中的所有相邻重复项
题目描述:
给出由小写字母组成的字符串 S
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:"abbaca" 输出:"ca" 解释: 例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
解题思路:
使用栈数据结构。每次入栈先检验数值与栈顶元素是否相等,相等就出栈,否则入栈。
最后将栈元素保存在字符串中,并反转字符串。
代码:
class Solution {
public:
string removeDuplicates(string s) {
stack<int> st;
for(auto c : s)
{
if(st.empty()) st.push(c);
else
{
int tp = st.top();
if(tp == c) st.pop();
else st.push(c);
}
}
string result;
while(!st.empty())
{
result += st.top();
st.pop();
}
reverse(result.begin(),result.end());
return result;
}
};