LeetCode 剑指 Offer II 栈 专题总结

  • 📚 博客主页:⭐️这是一只小逸白的博客鸭~⭐️
  • 👉 欢迎 关注❤️点赞👍收藏⭐️评论📝
  • 😜 小逸白正在备战实习,经常更新面试题LeetCode题解,欢迎志同道合的朋友互相交流~
  • 💙 若有问题请指正,记得关注哦,感谢~

往期文章 :

036. 后缀表达式

题目:

根据 逆波兰表示法,求该后缀表达式的计算结果。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:

  • 整数除法只保留整数部分。
  • 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例:

输入:tokens = [“2”,“1”,"+",“3”,"*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

提示:

  • 1 <= tokens.length <= 104
  • tokens[i] 要么是一个算符("+""-""*""/"),要么是一个在范围[-200, 200] 内的整数

逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 )
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * )

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

思路:

  • 遍历字符串数组
  • 遇到数字压栈
  • 遇到符号从栈中取两次栈顶元素进行符号计算
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> stack;
        for(int i = 0; i < tokens.size(); i++){
            if(tokens[i] == "+") {
                int y = stack.top(); stack.pop();
                int x = stack.top(); stack.pop();
                stack.emplace(x + y);
            }else if(tokens[i] == "-") {
                int y = stack.top(); stack.pop();
                int x = stack.top(); stack.pop();
                stack.emplace(x - y);
            }else if(tokens[i] == "*") {
                int y = stack.top(); stack.pop();
                int x = stack.top(); stack.pop();
                stack.emplace(x * y);
            }else if(tokens[i] == "/") {
                int y = stack.top(); stack.pop();
                int x = stack.top(); stack.pop();
                stack.emplace(x / y);
            }else {
                stack.emplace(stoi(tokens[i]));
            }
        }
        return stack.top();
    }
};

037. 小行星碰撞

题目:

给定一个整数数组 asteroids,表示在同一行的小行星。
对于数组中的每一个元素,其绝对值表示小行星的大小,正负表示小行星的移动方向(正表示向右移动,负表示向左移动)。每一颗小行星以相同的速度移动。
找出碰撞后剩下的所有小行星。碰撞规则:两个行星相互碰撞,较小的行星会爆炸。如果两颗行星大小相同,则两颗行星都会爆炸。两颗移动方向相同的行星,永远不会发生碰撞。

示例:

输入:asteroids = [5,10,-5]
输出:[5,10]
解释:10 和 -5 碰撞后只剩下 10 。 5 和 10 永远不会发生碰撞。

提示:

  • 2 <= asteroids.length <= 104
  • -1000 <= asteroids[i] <= 1000
  • asteroids[i] != 0

思路:

用动态数组模拟栈
入栈:当栈为空 or 当前数为正数 or 栈中元素为负数
出栈:

  • 栈不为空 and 栈顶正数 and 栈顶小于当前负数的绝对值(第三个条件包含了当前数为负数的条件)
  • 栈不为空 and 当前数为负数 and 栈顶 等于 当前数
class Solution {
public:
    vector<int> asteroidCollision(vector<int>& asteroids) {
        vector<int> res;
        for(int i : asteroids) {
            while(!res.empty() && res.back() > 0 && res.back() < -i) {
                res.pop_back();
            }
            if(!res.empty() && i < 0 && res.back() == -i) {
                res.pop_back();
            } else if(res.empty() || i > 0 || res.back() < 0) {
                res.push_back(i);
            }
        }
        return res;
    }
};

038. 每日温度

题目:

请根据每日 气温 列表 temperatures ,重新生成一个列表,要求其对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

提示:

  • 1 <= temperatures.length <= 105
  • 30 <= temperatures[i] <= 100

思路:

单调栈(递减)
栈中存储数组下标(方便计算天数)
while :如果栈顶小于当前数,相当于遇到高温天气,更新低温天气 res 的值

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int n = temperatures.size();
        vector<int> res(n);
        stack<int> sta;
        for(int i = 0; i < n; i++) {
            while(!sta.empty() && temperatures[sta.top()] < temperatures[i]) {
                res[sta.top()] = i - sta.top();
                sta.pop();
            }
            sta.push(i);
        }
        return res;
    }
};

039. 直方图最大矩形面积(困难)

题目:

给定非负整数数组 heights ,数组中的数字用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例:

在这里插入图片描述

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

思路:

单调栈(递增)
详细题解:《剑指offer 2 面试题39》 书中算法C++实现

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        //单调递增的栈,栈里元素存储数组下标
        stack<int> sta;
        //-1为哨兵,计算宽度时使用
        sta.push(-1);
        int maxArea = 0;
        for(int i = 0; i < heights.size(); i++) {
            //遇到小于栈顶元素时,计算栈顶元素的面积
            while(sta.top() != -1 && heights[sta.top()] > heights[i]) {
                int height = heights[sta.top()]; sta.pop();
                int width = i - sta.top() - 1;
                maxArea = max(maxArea, height * width);
            }
            sta.push(i);
        }
        //当有剩余元素时,即里面都是单调递增元素,将右边添加一个0即可计算面积,0的下标-->heights.size()
        while(sta.top() != -1) {
            int height = heights[sta.top()]; sta.pop();
            //计算的又边界为0的下标 heights.size()
            int width = heights.size() - sta.top() - 1;
            maxArea = max(maxArea, height * width);
        }
        return maxArea;
    }
};

040. 矩阵中最大的矩形(困难)

题目:

给定一个由 0 和 1 组成的矩阵 matrix ,找出只包含 1 的最大矩形,并返回其面积。
注意:此题 matrix 输入格式为一维 01 字符串数组。

示例:

在这里插入图片描述
输入:matrix = [“10100”,“10111”,“11111”,“10010”]
输出:6
解释:最大矩形如上图所示。

提示:

  • rows == matrix.length
  • cols == matrix[0].length
  • 0 <= row, cols <= 200
  • matrix[i][j]'0''1'

思路:

将这题转换成上一题 剑指 Offer II 039. 直方图最大矩形面积(困难) 的扩展
因为最大矩阵一定是以矩阵的某一行为底边的,所以可以遍历各行,将每行的数组带入上题代码得到该行最大矩阵
第一行等效为 [1, 0, 1, 0, 0]
第二行等效为 [2, 0, 2, 1, 1]
第三行等效为 [3, 1, 3, 2, 2]
第四行等效为 [4, 0, 0, 3, 0]
详细题解:《剑指offer 2 面试题40》 书中算法C++实现

class Solution {
public:
    int maximalRectangle(vector<string>& matrix) {
        if(matrix.size() == 0) return 0;
        vector<int> height(matrix[0].size());
        int maxArea = 0;
        for(int i = 0; i < matrix.size(); i++) {
            for(int j = 0; j < matrix[0].size(); j++) {
                if(matrix[i][j] == '0') {
                	//表示这列无矩阵
                    height[j] = 0;
                }else {
                	//该列高
                    height[j] += matrix[i][j] - '0';
                }
            }
            maxArea = max(maxArea, largestRectangleArea(height));
        }
        return maxArea;
    }
    int largestRectangleArea(vector<int>& heights) {
        //单调递增的栈,栈里元素存储数组下标
        stack<int> sta;
        //-1为哨兵,计算宽度时使用
        sta.push(-1);
        int maxArea = 0;
        for(int i = 0; i < heights.size(); i++) {
            //遇到小于栈顶元素时,计算栈顶元素的面积
            while(sta.top() != -1 && heights[sta.top()] > heights[i]) {
                int height = heights[sta.top()]; sta.pop();
                int width = i - sta.top() - 1;
                maxArea = max(maxArea, height * width);
            }
            sta.push(i);
        }
        //当有剩余元素时,即里面都是单调递增元素,将右边添加一个0即可计算面积,0的下标-->heights.size()
        while(sta.top() != -1) {
            int height = heights[sta.top()]; sta.pop();
            //计算的又边界为0的下标 heights.size()
            int width = heights.size() - sta.top() - 1;
            maxArea = max(maxArea, height * width);
        }
        return maxArea;
    }
};
  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小逸白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值