1. 逆波兰表达式
逆波兰表达式就是便于计算机执行数值运算的方法,属于栈的应用规则就是遇到数字就将数字入栈,遇到运算符就将栈顶元素和第二个元素拿出来运算,将结果再入栈
int evalRPN(vector<string>& tokens) {
stack<long long> st;
for (int i = 0; i < tokens.size(); i++) {
// if (tokens[i] >= "0" && tokens[i] <= "9") { // 这样写不合法,判断不了
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);
else if (tokens[i] == "-") st.push(num2-num1);
else if (tokens[i] == "*") st.push(num2*num1);
else if (tokens[i] == "/") st.push(num2/num1);
}else {
st.push(stoll(tokens[i]));
}
}
return st.top();
}
2. 滑动窗口最大值
自定义单调队列维护窗口最大值,原则如下:(窗口大小为k)
1. 使用双向队列来实现窗口
2. 窗口内的元素是单调递减的(也可以递增,只要方法稍作改变)
3. 队列内最多只有k个元素
具体操作过程(按照单调递增):
1. 先处理第一个窗口(找到第一个窗口的最大值),然后才开始滑动过程
2. 滑动:先把最早进入窗口的元素移出队列,然后将新元素从队头加入窗口,并且把比他小的元素都pop_front()
3. 收集最大值:队列尾部的元素
class Myqueue {
public:
// 初始化
deque<int> que;// deque为双端队列可以在头部和尾部进行插入和删除结合了栈和队列的特点
// 方法保证窗口是移动的
void pop(int value) {
// 为什么相等才移除
// 因为value的值是按照加入窗口的顺序传入的,但是队列中的元素是按照大小来存放的
// 如果一个窗口的最大值是最后加入该窗口的元素,它会自动将之前的元素移除窗口,
// 相当于提前完成了下一次滑动
// 也就是因为value是按照加入窗口的顺序依次传入的,确保当最先进入窗口的元素是最大值时
// 保持窗口的滑动
if (!que.empty() && value == que.back()) {
que.pop_back();
}
}
void push(int value) {
// 维护最大值
while(!que.empty() && que.front() < value) {
que.pop_front();
}
que.push_front(value);
}
int myMax() {
return que.back();
}
};
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> maxValue;
Myqueue que;
// 先处理第一个窗口
for(int i = 0; i < k; i++) {
que.push(nums[i]);
}
maxValue.push_back(que.myMax());
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i-k]);
que.push(nums[i]);
maxValue.push_back(que.myMax());
}
return maxValue;
}
对于窗口的滑动过程(移除上一个窗口最早加入的元素)还可以这样理解,分两种情况看:
1. 上一个窗口的最大值是最早加入窗口的,元素下标为i-k,移除他,然后加入新元素下标i,整列队列
2. 上一个窗口的最大值不是最早加入的元素,那么在更新上一个窗口的过程中,最早加入的元素已经被自动移除