目录
stoll()将字符串其作为long long int类型的值返回。
这个都知道,队列是先进先出,栈是先进后出
但是要知道--栈和队列进和出是push和pop
C++中stack、queue 是容器么?
不算是容器,因为其是靠其他容器来实现的,具体使用何种容器来实现栈、队列是可选择的,所以栈只能算是container adapter(容器适配器),不算容器
我们使用的STL中stack、queue是如何实现的?
vector,deque,list都可以,主要是数组和链表的实现
stack 提供迭代器来遍历stack、queue空间么?
不提供
函数调用
文中涉及到的常用函数调用
stack | push、pop、top |
queue | push、pop、front、back |
priority_queue | push、pop、top |
deque | push_front、push_back、pop_front、pop_back、front、back |
232、用栈实现队列
为什么不直接使用pop函数,而使用top函数
pop(), 返回void,top(),返回栈顶的引用。
两个栈,一个输入一个输出
尤其要注意出队列是,当栈2为空,循环将栈1的元素压入栈2;不为空就出栈,并将栈中此元素清掉
class MyQueue {
public:
stack<int> StaIn;
stack<int> StaOut;
MyQueue() {
}
void push(int x) {
StaIn.push(x);
}
int pop() {
if(StaOut.empty()) {
while(!StaIn.empty()) {
StaOut.push(StaIn.top());
StaIn.pop();
}
}
int result = StaOut.top();
StaOut.pop();
return result;
}
int peek() {
int PeekResult = pop();
StaOut.push(PeekResult);
return PeekResult;
}
bool empty() {
if(StaIn.empty() && StaOut.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();
*/
225.、用队列实现栈
可以用一个队列实现栈,尤其需要注意出栈要怎么写
只用将最后进入队列的元素保留,其他队列元素全都重新填入队列,并将队列此元素清除掉(pop)
也可以使用两个队列实现栈,需要注意出栈怎么写
que1留下最后一个元素,将que1剩余元素导入que2,que1留下最后一个元素就是最后一个元素;
接着将que2赋值给que1,将que2清空
class MyStack {
public:
queue<int> que1;
queue<int> que2; // 辅助队列,用来备份
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
que1.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int size = que1.size();
size--;
while (size--) { // 将que1 导入que2,但要留下最后一个元素
que2.push(que1.front());
que1.pop();
}
int result = que1.front(); // 留下的最后一个元素就是要返回的值
que1.pop();
que1 = que2; // 再将que2赋值给que1
while (!que2.empty()) { // 清空que2
que2.pop();
}
return result;
}
/** Get the top element. */
int top() {
return que1.back();
}
/** Returns whether the stack is empty. */
bool empty() {
return que1.empty();
}
};
20、有效的括号
使用栈解决有效的括号问题
class Solution {
public:
//有三种情况返回false 1:左括号多了,2:右括号多了,3:左右括号不匹配
bool isValid(string s) {
stack<char> Sta;
for(char c : s) {
if(c == '(') Sta.push(')');
else if (c == '{') Sta.push('}');
else if (c == '[') Sta.push(']');
else if (Sta.empty() || c != Sta.top()) return false;//2和3
else Sta.pop();
}
return Sta.empty();//此时返回false是1,返回true就是对了
}
};
1047、删除字符串中的所有相邻重复项
1047. 删除字符串中的所有相邻重复项 - 力扣(Leetcode)
这个题也是使用栈进行解决,匹配问题是栈的强项
递归调用就是会把函数的局部变量、参数和返回地址等压入栈中,但在企业项目开发中,尽量不要使用递归,容易无限递归
class Solution {
public:
string removeDuplicates(string s) {
stack<char> sta;//创建sta
//遍历string s
for (char sf : s) {
//如果是空的和s中的字符不等于st的字符,就往st里放字符
//其他种情况就要pop
if (sta.empty() || sf != sta.top()) {
sta.push(sf);
} else {
sta.pop();
}
}
//将栈中元素放到结果result字符串中
string result = "";
while (!sta.empty()) {
result += sta.top();
sta.pop();
}
//翻转一下字符串
reverse(result.begin(),result.end());
return result;
}
};
150、逆波兰表达式求值
stol()将字符串其作为long int类型的值返回。
stoll()将字符串其作为long long int类型的值返回。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
// 力扣修改了后台测试数据,需要用longlong
stack<long long> st;
for (int i = 0; i < tokens.size(); i++) {
if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
long long num1 = st.top();
st.pop();
long long num2 = st.top();
st.pop();
if (tokens[i] == "+") st.push(num2 + num1);
if (tokens[i] == "-") st.push(num2 - num1);
if (tokens[i] == "*") st.push(num2 * num1);
if (tokens[i] == "/") st.push(num2 / num1);
} else {
st.push(stoll(tokens[i]));
}
}
int result = st.top();
st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
return result;
}
};
239. 滑动窗口最大值
使用单调队列的经典题目
自己实现一个单调队列,滑动窗口就是这个队列,具有以下功能:
1、pop滑动窗口删除元素
2、push滑动窗口添加元素
3、front滑动窗口返回最大值
维护滑动窗口有可能成为最大值的一个序列,主要就是维持出口的元素
如果push一个元素,而之前的元素小于这个元素,就将原来的元素pop掉
如果pop的元素是当前队列的出口元素就pop,否则不动
class Solution {
private:
class MyQueue { //单调队列(从大到小)
public:
deque<int> que; // 使用deque来实现单调队列
// 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
// 同时pop之前判断队列当前是否为空。
void pop(int value) {
if (!que.empty() && value == que.front()) {
que.pop_front();
}
}
// 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
// 这样就保持了队列里的数值是单调从大到小的了。
void push(int value) {
while (!que.empty() && value > que.back()) {
que.pop_back();
}
que.push_back(value);
}
// 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
int front() {
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> result;
for (int i = 0; i < k; i++) { // 先将前k的元素放进队列
que.push(nums[i]);
}
result.push_back(que.front()); // result 记录前k的元素的最大值
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i - k]); // 滑动窗口移除最前面元素
que.push(nums[i]); // 滑动窗口前加入最后面的元素
result.push_back(que.front()); // 记录对应的最大值
}
return result;
}
};
347.前 K 个高频元素
这个题还是挺难的,再写一遍不一定可以写对
1.统计元素出现频率 map
2.对频率排序 优先级队列
3.找出前k个高频元素
那么为什么不用快速排序方法,是因为需要将map转换为vector的结构
因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
class Solution {
public:
//排序-小顶堆
class mycomparison {
public:
bool operator() (const pair<int, int> &a, const pair<int, int> &b) {
return a.second > b.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
//1.统计出现频率
unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
map[nums[i]]++;
}
//2.对频率进行排序
priority_queue<pair<int, int>,vector<pair<int, int>>, mycomparison> pri_que;
//固定k大小的小顶堆
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
pri_que.push(*it);
if (pri_que.size() > k) {
pri_que.pop();
}
}
//3.找出结果,化成vector
vector<int> result(k);
for (int j = k - 1; j >= 0; j--) {
result[j] = pri_que.top().first;
pri_que.pop();
}
return result;
}
};
优先级队列
具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的,而堆是由二叉树实现的
优先级队列(priority_queue):有大顶堆和小顶堆,都是一颗完全二叉树,其中大顶堆中每个结点的值都不小于其左右孩子的值(堆头是最大元素),小顶堆中每个结点的值都不大于其左右孩子的值(堆头是最小元素)
priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。Functional默认大顶堆,容器类型默认vector
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;
//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)