一、栈与队列的关系
1. 232用栈实现队列
class MyQueue
{
public:
stack<int>stack_in;
stack<int>stack_out;
MyQueue()
{
}
void push(int x)
{
stack_in.push(x);
}
int pop()
{
if(stack_out.empty())//空的就是true
{
while(!stack_in.empty())
{
stack_out.push(stack_in.top());
stack_in.pop();
}
}
int result = stack_out.top();
stack_out.pop();
return result;
}
int peek()
{
if(stack_out.empty())//空的就是true
{
while(!stack_in.empty())
{
stack_out.push(stack_in.top());
stack_in.pop();
}
}
int result=stack_out.top();
return result;
}
bool empty()
{
if (stack_in.empty()&&stack_out.empty())
{
return true;
}
else
{
return false;
}
}
};
/**
* 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();
*/
2. 255用两个队列实现栈
class MyStack {
public:
queue<int> queue1;//这是用来模仿栈的
queue<int> queue2;
MyStack() {
}
void push(int x)
{
queue1.push(x);
}
int pop()
{
int size=queue1.size();
size--;
while(size--)
{
queue2.push(queue1.front());
queue1.pop();//从头部弹出元素
}
int result=queue1.back();
queue1.pop();
queue1=queue2;
while (!queue2.empty())
{
// 清空queue_out
queue2.pop();
}
return result;
}
int top()
{
int result=queue1.back();
return result;
}
bool empty()
{
if(queue1.empty())
{
return true;
}
else
{
return false;
}
}
};
/**
* 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();
*/
补充:用一个队列实现栈
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();
}
二、栈与匹配
1.20有效的括号(此题想了很久,最后看了答案)
题目 难度:简单
解题思路:
- 先判断字符串大小是否是2的倍数,不是2的倍数一定匹配不上!
- 遍历字符串:
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false - 最后判断栈是否为空,空的栈括号能匹配上,不是空的栈匹配不上!
class Solution
{
public:
stack<char> s1;
bool isValid(string s)
{
int size=s.length();
if(size%2!=0)
{
return false;
}
//if(size==0) return true;
for(int i=0;i<size;i++)
{
if(s[i]=='(')
{
s1.push(')');
}
else if(s[i]=='{')
{
s1.push('}');
}
else if(s[i]=='[')
{
s1.push(']');
}
else if (s1.empty() || s1.top() != s[i]) //第三种和第二种
{
return false;
}
else if(s1.top()==s[i]) s1.pop();// st.top() 与 s[i]相等,栈弹出元素
}
// 第一种情况:此时我们已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return true
return s1.empty();
}
};
2.1047 删除字符串中的所有相邻重复项
题目 难度:简单
class Solution {
public:
stack<char> sta;
string removeDuplicates(string s)
{
string s_new;
int size=s.length();
for(int i=0;i<size;i++)
{
if(sta.empty() || s[i]!= sta.top())
{
sta.push(s[i]);
}
else
{
sta.pop();
}
}
while(!sta.empty())
{
s_new+=sta.top();
sta.pop();
}
reverse(s_new.begin(), s_new.end());
return s_new;
}
};
总结:
- 字符串拼接:
(1)+
(2) apeend - 字符串反转:
string s;
reverse(s.begin(), s.end());
三、栈之逆波兰
1.150. 逆波兰表达式求值
题目 难度:中等
规则:从左往右遍历这个表达式的每个数字和符号,凡是遇到数字就进栈,遇到符号,就将栈顶的两个数字出栈,进行运算,再将运算结果进栈。
class Solution
{
public:
int evalRPN(vector<string>& tokens)
{
int size=tokens.size();
stack<int> sta;
for(int i=0;i<size;i++)
{
if((tokens[i]!="+")&&(tokens[i]!="-")&&(tokens[i]!="*")&&(tokens[i]!="/"))
{
sta.push(stoi(tokens[i]));
}
else if(tokens[i]=="+")
{
int a=sta.top();
sta.pop();
int b=sta.top();
sta.pop();
sta.push(a+b);
}
else if(tokens[i]=="-")
{
int a=sta.top();
sta.pop();
int b=sta.top();
sta.pop();
sta.push(b-a);
}
else if(tokens[i]=="*")
{
int a=sta.top();
sta.pop();
int b=sta.top();
sta.pop();
sta.push(a*b);
}
else if(tokens[i]=="/")
{
int a=sta.top();
sta.pop();
int b=sta.top();
sta.pop();
sta.push(b/a);
}
}
int result=sta.top();
return result;
}
};
总结:
字符串与数字之间的转换:
stod()//字符串转double
stof()//字符串转float
stoi()//字符串转int
stol()//字符串转long
stold()//字符串转double
stoll()//字符串转long long
string to_string(待转换的数字)
四、队列之优先队列
-
什么是优先级队列呢?
其实就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。 -
而且优先级队列内部元素是自动依照元素的权值排列。那么它是如何有序排列的呢?
缺省情况下priority_queue利用max-heap(大顶堆)完成对元素的排序,这个大顶堆是以vector为表现形式的complete binary tree(完全二叉树)。
1.347 前 K 个高频元素
题目 难度:简单
-
priority_queue<Type, Container, Functional>
Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
如果不写后两个参数,那么容器默认用的是 vector,比较方式默认用 operator<,也就是优先队列是大顶堆(less),队头元素最大,本题为小顶堆(greater)。 -
emplace、emplace_front、emplace_back分别对应insert、push_front和push_back。
class KthLargest {
public:
int K;
priority_queue<int,vector<int>,greater<int>> que;//小顶堆:从小到大
KthLargest(int k, vector<int>& nums)
{
K=k;
int size=nums.size();
for(int i=0;i<size;i++)
{
que.push(nums[i]);//将nums里面的元素进行从小到大排序
}
for(int j=0;j<(size-k);j++)//nums里面的元素只剩k个
{
que.pop();
}
}
int add(int val)
{
que.push(val);
int size_new=que.size();
for(int j=0;j<(size_new-K);j++)
{
que.pop();
}
return que.top();
}
};
五、队列之单调队列
- 单调队列:顾名思义其中所有的元素都是单调的(递增或者递减),承载的技术数据结构是队列,实现是双端队列,队头元素为窗口的最大最小元素。
队头删除不符合有效窗口的元素,队尾删除不符合最值的候选元素。 - 但是单调队列不是真正的队列,因为队列都是先进先出,而单调队列不符合FIFO。
- 删头操作:队头元素出队列。
去尾操作:队尾元素出队列,待新元素从队尾入队,从队尾开始删除影响队列单调性的元素。 - 但是要保证:插入必须在去尾之后来。
1.239滑动窗口最大值
题目 难度:困难
class MyQueue {
public:
void pop(int value) {
}
void push(int value) {
}
int front() {
return que.front();
}
};
设计单调队列的时候,pop,和push操作要保持如下规则:
- push(value):如果push的元素value大于入口元素的数值,那么就将队列入口(尾部)的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止。
- pop(value):如果窗口移除的元素value等于单调队列的出口(头部)元素,那么队列弹出元素,否则不用任何操作。
- que.front()就可以返回当前窗口的最大值。
class Solution {
public:
class MyQueue
{
public:
deque<int> que; // 使用deque来实现单调队列
//去尾
void push(int value)
{
while(!que.empty()&&value>que.back())
{
que.pop_back();//队尾删除不符合最值的候选元素
}
que.push_back(value);//插入必须在去尾后面
}
//删头
void pop(int value)
{
if(!que.empty()&&value==que.front())
{
que.pop_front();//队头删除不符合有效窗口的元素
}
}
int front()
{
return que.front();
}
};
vector<int> maxSlidingWindow(vector<int>& nums, int k)
{
vector<int> max_value;
MyQueue myque;
for (int i = 0; i < k; i++) // 先将前k的元素放进队列
{
myque.push(nums[i]);
}
max_value.push_back(myque.front());
for(int i=k;i<nums.size();i++)
{
myque.pop(nums[i-k]);
myque.push(nums[i]);
int max=myque.front();
max_value.push_back(max);
}
return max_value;
}
};