leetcode刷题记录05(2023-04-16)【柱状图中最大的矩形(单调栈) | 二叉树的中序遍历(递归能过就别闹) | 最大矩形(单调栈,转换为柱状图那题) | 不同的二叉搜索树(dp)】

84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

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

示例 2:
输入: heights = [2,4]
输出: 4

提示:
1 <= heights.length <=105
0 <= heights[i] <= 104

这道题目我最开始是使用动态规划做的,时间复杂度是 O ( n 2 ) O(n^2) O(n2),空间复杂度是 O ( n 2 ) O(n^2) O(n2)

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        vector<vector<int>> dp(n, vector<int>(n, 0));
        int maxArea = 0;
        for (int i = 0; i < n; i++) {
            dp[i][i] = heights[i];
            if (maxArea < dp[i][i])maxArea = dp[i][i];
            for (int j = i + 1; j < n; j++) {
                dp[i][j] = min(dp[i][j - 1], heights[j]);
                if (maxArea < (j - i + 1) * dp[i][j])maxArea = (j - i + 1) * dp[i][j];
            }
        }
        return maxArea;
    }
};

但是提交后,超时了。

后面看了题解,发现我上面的操作其实可以使用单调栈进行优化,将时间和空间复杂度都降低到 O ( n ) O(n) O(n) 复杂度。

主要思想就是维护一个单调递增栈,在这个栈中,heights 值是严格单调递增的。(即:栈中任意两个元素之间的元素都是严格大于第一个元素,小于第二个元素的)所以我们只要找到一个小于它的值,那么它右边的这些值都是大于这个值的。

这样对于一个不严格单调递增的值,我们就可以很容易找到左边比它小的第一个值。

然后倒着遍历,很快又可以找到右边比他小的第一个值。

最后遍历一遍heights,对于每一个位置,求解它的面积,并保存最大值。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int>stk;
        int n = heights.size();
        vector<int> left(n, 0), right(n, 0);

        for (int i = 0; i < n; i++) {
            while (!stk.empty() && heights[stk.top()] >= heights[i]) {
                stk.pop();
            }            
            left[i] = stk.empty() ? -1 : stk.top();
            stk.push(i);
        }

        stk = stack<int>();
        for (int i = n-1; i >= 0; i--) {
            while (!stk.empty() && heights[stk.top()] >= heights[i]) {
                stk.pop();
            }            
            right[i] = stk.empty() ? n : stk.top();
            stk.push(i);
        }

        int maxArea = 0;

        for (int i = 0; i < n; i++) {
            maxArea = max(maxArea, (right[i] - left[i] - 1) * heights[i]);
        }
        return maxArea;
    }
};

94. 二叉树的中序遍历

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

示例 1:

在这里插入图片描述

输入:root = [1,null,2,3]
输出:[1,3,2]

示例 2:
输入:root = []
输出:[]

示例 3:
输入:root = [1]
输出:[1]

提示:
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

#include<vector>
#include<iostream>
using namespace std;

// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
 
class Solution {
    void digui(TreeNode* root, vector<int>& vec) {
        if (root->left != nullptr)digui(root->left, vec);
        vec.push_back(root->val);
        if (root->right != nullptr)digui(root->right, vec);
    }
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        if (root == nullptr)return result;
        digui(root, result);
        return result;
    }
};

递归法很简单,迭代法则主要运用了栈的思想,实现如下:

// 迭代法
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> stk;
        vector<int> res;
        while (root != nullptr || !stk.empty()) {
            while (root) {
                stk.push(root);
                root = root->left;
            }
            root = stk.top();
            stk.pop();
            res.push_back(root->val);
            root = root->right;
        }
        return res;
    }
};

85. 最大矩形

给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例 1:

在这里插入图片描述

输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:6
解释:最大矩形如上图所示。

示例 2:
输入:matrix = []
输出:0

示例 3:
输入:matrix = [[“0”]]
输出:0

示例 4:
输入:matrix = [[“1”]]
输出:1

示例 5:
输入:matrix = [[“0”,“0”]]
输出:0

提示:

r o w s = = m a t r i x . l e n g t h rows == matrix.length rows==matrix.length
c o l s = = m a t r i x [ 0 ] . l e n g t h cols == matrix[0].length cols==matrix[0].length
1 < = r o w , c o l s < = 200 1 <= row, cols <= 200 1<=row,cols<=200

m a t r i x [ i ] [ j ] 为 ′ 0 ′ 或 ′ 1 ′ matrix[i][j] 为 '0' 或 '1' matrix[i][j]01

这道题目主要利用了上面一道题目的思路,将其转化为了 84 题。

引用一下题解的图1

在这里插入图片描述

#include<vector>
#include<stack>
#include<iostream>

using namespace std;

class Solution {
    int largestRectangleArea(vector<int>& heights) {
        stack<int>stk;
        int n = heights.size();
        vector<int> left(n, 0), right(n, 0);

        for (int i = 0; i < n; i++) {
            while (!stk.empty() && heights[stk.top()] >= heights[i]) {
                stk.pop();
            }
            left[i] = stk.empty() ? -1 : stk.top();
            stk.push(i);
        }

        stk = stack<int>();
        for (int i = n - 1; i >= 0; i--) {
            while (!stk.empty() && heights[stk.top()] >= heights[i]) {
                stk.pop();
            }
            right[i] = stk.empty() ? n : stk.top();
            stk.push(i);
        }

        int maxArea = 0;

        for (int i = 0; i < n; i++) {
            maxArea = max(maxArea, (right[i] - left[i] - 1) * heights[i]);
        }
        return maxArea;
    }
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();

        vector<int> heights(n, 0);

        int maxArea = 0;
        for (int j = 0; j < n; j++) {
            if (matrix[0][j] == '1') {
                heights[j] = 1;
                maxArea = 1;
            }
        }

        maxArea = max(maxArea, largestRectangleArea(heights));

        for (int i = 1; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '1') {
                    heights[j]++;
                }
                else {
                    heights[j] = 0;
                }
            }
            maxArea = max(maxArea, largestRectangleArea(heights));
        }

        return maxArea;
    }
};

int main() {
    Solution sol;
    //vector<vector<char>> vec = {
    //    {'1','0','1','0','0'},
    //    {'1','0','1','1','1'},
    //    {'1','1','1','1','1'},
    //    {'1','0','0','1','0'}
    //};

    vector<vector<char>> vec = {
    {'1'}};

    cout << sol.maximalRectangle(vec);
}

96. 不同的二叉搜索树

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

在这里插入图片描述

输入:n = 3
输出:5

示例 2:
输入:n = 1
输出:1

提示:
1 < = n < = 19 1 <= n <= 19 1<=n<=19

这道题目的思路就是,因为二叉树是有序的,因此,推导一下他的最优子结构如下:

把他想象成一个有序的数组,数组一共有n种情况(即各个节点分别作为root节点)

考虑这些情况,假设一共有5个节点,第2个节点作为root节点后,左边有1个,右边有3个,总共的结果就是 v e c [ 1 ] × v e c [ 3 ] vec[1]\times vec[3] vec[1]×vec[3]

显然,1个节点有1种情况,2个节点有2种情况,然后我们从3开始遍历,进行动态规划到n即可。

二者相乘就是当前根节点下总共可能的搜索结果。

#include<iostream>
#include<vector>
using namespace std;

class Solution {
public:
    int numTrees(int n) {
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 2;
        }
        vector<int> vec(n + 1, 0);
        int res = 0;
        vec[0] = 1;
        vec[1] = 1;
        vec[2] = 2;
        for (int i = 3; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                int left = j - 1;
                int right = i - j;
                res += vec[left] * vec[right];
            }
            vec[i] = res;
            res = 0;
        }
        return vec[n];
    }
};

int main() {
    Solution sol;
    cout << sol.numTrees(4);
}

答案的题解更加简洁一些,在此也记录一下:

class Solution {
public:
    int numTrees(int n) {
        vector<int> G(n + 1, 0);
        G[0] = 1;
        G[1] = 1;

        for (int i = 2; i <= n; ++i) {
            for (int j = 1; j <= i; ++j) {
                G[i] += G[j - 1] * G[i - j];
            }
        }
        return G[n];
    }
};

  1. https://leetcode.cn/problems/maximal-rectangle/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-1-8/ ↩︎

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Cherries Man

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

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

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

打赏作者

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

抵扣说明:

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

余额充值