目录
基础知识
用栈实现队列
用队列实现栈
栈的拿手好戏
删除字符串中的所有相邻重复项
逆波兰表达式求值
滑动窗口最大值
前k个高频元素
基础知识
栈 | 队列 |
stack | queue |
先进后出 | 先进先出 |
无迭代器 | 无迭代器 |
容器设配器 | 容器设配器 |
vector deque list | vector deque list |
C++标准库版本
HP STL | PJ STL | SGI STL |
deque是双向的队列,封住一端就是stack
用栈实现队列
利用两个栈实现对队列的进出操作。首先要明确这两个栈分别是进栈,出栈,当队列数据进入之后,就把数据存入进栈,再把进栈数据存入出栈,那么这时出栈再出去的数据就和队列保持一致了。
push
此时在队列中就是把数据存入队列中,那么此时我们就把该数据存入进栈中
pop
此时在队列中是把最开始存入的元素出去,那么我就相当于操作出栈的第一个元素。因此我们先把数据存入进栈,出栈。这时出栈没有数据,为空,因此先判断出栈是否为空,然后把进栈的数据存入
if(stOut.empty()){
while(!stIn.empty()){
stOut.push(stIn.top());
stIn.pop();
}
}
这时,出栈已经有了数据,要出去第一个数据只需要把出栈第一个数据出去
int result = stOut.top();
stOut.pop();
peek
返回队列的第一个元素,和pop很像,一个是弹出,一个是返回值,那么就相当于我们不pop,只得到值,只需要在pop之后把数据push进去
int peek() {
int res = this->pop(); // 直接使用已有的pop函数
stOut.push(res); // 因为pop函数弹出了元素res,所以再添加回去
return res;
}
232. 用栈实现队列 - 力扣(LeetCode)https://leetcode.cn/problems/implement-queue-using-stacks/submissions/
用队列实现栈
利用一个队列模拟栈的过程,栈出去的元素类似于把队列前面的元素再插入一次,再把队列最后一个元素出去。
class MyStack {
public:
queue<int>que;
MyStack() {
}
void push(int x) {
que.push(x);
}
int pop() {
int size = que.size()-1;
while(size--){
que.push(que.front());
que.pop();
}
int result = que.front();
que.pop();
return result;
}
int top() {
return que.back();
}
bool empty() {
return que.empty();
}
};
/**
* 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();
*/
225. 用队列实现栈 - 力扣(LeetCode)https://leetcode.cn/problems/implement-stack-using-queues/submissions/
栈的拿手好戏
用栈的原因是因为左右括号存在就直接抵消,且存在3种情况。
注意事项:因为我们是遇到左括号插入右括号,这是分别字符串和栈顶元素比价
1.当字符串结束在,栈中还有元素,不匹配
2.当字符串遍历到右括号,且和栈顶不一样,则不匹配
3.当字符串遍历到右括号,且栈为空,则没有对应的左括号,则不匹配。
class Solution {
public:
bool isValid(string s) {
stack<char>stk;
unordered_map<char, char> map = {
{')', '('},
{']', '['},
{'}', '{'}
};
for (auto ch : s)
{
if (map.count(ch))//判断是不是右括号
{
//栈为空,或者栈顶不匹配
if (stk.empty() || stk.top() != map[ch])
{
return false;
}
stk.pop();
}
else//找到了左括号
{
stk.push(ch);
}
}
return stk.empty();
}
};
删除字符串中的所有相邻重复项
利用一个栈,把数据进行存放,每次放之前判断栈顶是不是一样,一样则不存该元素并且出栈栈顶这个元素,如果不一样则直接存放
for(auto ch : s){
if(sta.empty() || sta.top()!=ch){
sta.push(ch);
}else{
sta.pop();
}
}
当字符串遍历结束之后,那么sta中保留的就是我们需要的答案,此时只需要出栈就行,但要注意,出栈元素的顺序和输入顺序相反,因此需要reverse
class Solution {
public:
string removeDuplicates(string s) {
stack<char>sta;
for(auto ch : s){
if(sta.empty() || sta.top()!=ch){
sta.push(ch);
}else{
sta.pop();
}
}
string result = "";
while(!sta.empty()){
result += sta.top();
sta.pop();
}
reverse(result.begin(),result.end());
return result;
}
};
逆波兰表达式求值
利用一个栈进行存放数,当遇到符号就把栈里面的前两个拿出来进行处理,然后继续存放,直到所有数据
stack<long long>sta;
for(int i = 0; i < tokens.size(); i++){
if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/"){
long long num1 = sta.top();
sta.pop();
long long num2 = sta.top();
sta.pop();
if(tokens[i] == "+") sta.push(num1 + num2);
if(tokens[i] == "-") sta.push(num2 - num1);
if(tokens[i] == "*") sta.push(num1 * num2);
if(tokens[i] == "/") sta.push(num2 / num1);
}else{
sta.push(stoll(tokens[i]));
}
}
此时数据已经处理结束,只需要把栈顶元素取出来就行
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long>sta;
for(int i = 0; i < tokens.size(); i++){
if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/"){
long long num1 = sta.top();
sta.pop();
long long num2 = sta.top();
sta.pop();
if(tokens[i] == "+") sta.push(num1 + num2);
if(tokens[i] == "-") sta.push(num2 - num1);
if(tokens[i] == "*") sta.push(num1 * num2);
if(tokens[i] == "/") sta.push(num2 / num1);
}else{
sta.push(stoll(tokens[i]));
}
}
int result = sta.top();
sta.pop();
return result;
}
};
滑动窗口最大值
本题思路自己创建一个队列,该队列可以实现
1.每次插入时,如果前面的元素小于当前插入,则把之前的元素就把出队列
2.每次删除时,先判断队列顶端是不是要删的,如果不是则不删,是则删
3.每次返回队列顶端元素,且该元素是队列中最大元素
class Solution {
private:
class MyQueue{
public:
deque<int>que;
void pop(int values){
if(!que.empty() && values == que.front()){
que.pop_front();
}
}
void push(int values){
while(!que.empty() && values > que.back()){
que.pop_back();
}
que.push_back(values);
}
int front(){
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int>ans;
for(int i=0;i<k;i++){
que.push(nums[i]);
}
ans.push_back(que.front());
for(int i=k;i<nums.size();i++){
que.pop(nums[i-k]);//去除第一个元素
que.push(nums[i]);//插入新的元素
ans.push_back(que.front());
}
return ans;
}
};
前k个高频元素
1.利用map记录每个元素和其次数
2.把map数据存放倒小顶堆,而且只放k个,超过k个则直接弹出堆顶,需要注意小顶堆的堆顶是最小的元素
class Solution {
public:
class mycomparison{
public:
bool operator()(const pair<int,int>& Ihs, const pair<int,int>& rhs){
return Ihs.second > rhs.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
//先把数据插入map中统计每个数的次数
unordered_map<int,int>umap;
for(int i=0;i<nums.size();i++){
umap[nums[i]]++;
}
//定义一个小顶堆,大小为k
priority_queue<pair<int,int>, vector<pair<int,int>>,mycomparison> pair_que;
//把map数据插进去,同时只插入k个
for(unordered_map<int,int>::iterator it =umap.begin();it!=umap.end();it++){
pair_que.push(*it);
if(pair_que.size()>k){
pair_que.pop();
}
}
vector<int>ans(k);
for(int i=k-1;i>=0;i--){
ans[i]=pair_que.top().first;
pair_que.pop();
}
return ans;
}
};