代码随想录Day40-单调栈:力扣第496e、503m、42h、84h题

496e. 下一个更大元素 I

题目链接
代码随想录文章讲解链接

方法一:单调栈+哈希表

用时:13m52s

思路

维护一个栈底到栈顶是单调递减的栈,从后往前遍历数组nums2,更新栈。nums2当前元素nums2[i]的下一个更大元素就是栈顶元素,若栈顶为空则表示nums2[i]之后没有比他大的元素。用哈希表存储,然后遍历nums1时再从哈希表中获取值。

  • 时间复杂度: O ( m + n ) O(m+n) O(m+n)
  • 空间复杂度: O ( m + n ) O(m+n) O(m+n)
C++代码
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        stack<int> stk;
        unordered_map<int, int> hashMap;
        vector<int> res(nums1.size(), 0);
        for (int i = nums2.size() - 1; i >= 0; --i) {
            while (!stk.empty() && nums2[i] > stk.top()) stk.pop();
            hashMap[nums2[i]] = stk.empty() ? -1 : stk.top();
            stk.push(nums2[i]);
        }
        for (int i = 0; i < res.size(); ++i) res[i] = hashMap[nums1[i]];
        return res;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


503m. 下一个更大元素II

题目链接
代码随想录文章讲解链接

方法一:单调栈

用时:16m28s

思路

维护一个栈底到栈顶单调递减的单调栈,遍历两遍数组。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int size = nums.size();
        stack<int> stk;
        vector<int> res(size, -1);
        for (int i = 0; i < size * 2; ++i) {
            while (!stk.empty() && nums[stk.top()] < nums[i % size]) {
                res[stk.top()] = nums[i % size];
                stk.pop();
            }
            stk.push(i % size);
        }
        return res;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


42h. 接雨水

题目链接
代码随想录文章讲解链接

方法一:按列统计

用时:28m51s

思路

分别统计每一列雨水的高度,设某一列i左边最高的柱子高度为L,列i右边最高的柱子高度为R,若min(L,R)大于列i的高度,则列i的雨水量为min(L,R) - height[i],否则为0。
先分别记录下每个位置左右两边最高的柱子的高度,然后再统计每一列雨水的高度。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int trap(vector<int>& height) {
        int size = height.size();
        vector<int> leftMax(size, 0);
        vector<int> rightMax(size, 0);
        int maxHeight = 0;
        int res = 0;

        // 记录每个位置左右两边最高的柱子高度
        for (int i = 0; i < size; ++i) {
            leftMax[i] = maxHeight;
            maxHeight = max(maxHeight, height[i]);
        }
        maxHeight = 0;
        for (int i = size - 1; i >= 0; --i) {
            rightMax[i] = maxHeight;
            maxHeight = max(maxHeight, height[i]);
        }

        // 统计每一列的雨水
        for (int i = 1; i < size - 1; ++i) {
            int minHeight = min(leftMax[i], rightMax[i]);
            if (minHeight > height[i]) res += minHeight - height[i];
        }
        return res;
    }
};

方法二:单调栈按行统计

用时:13m28s

思路

维护一个栈底到栈顶单调递减的单调栈。
遍历数组的时候,若遇到小于等于栈顶元素的元素,则直接入栈。
若遇到大于栈顶元素的元素,此时栈顶元素作为凹陷处,倒数第二个栈顶元素和当前元素作为两头的柱子,可以形成一个坑接住雨水,接住雨水的量等于(min(height[i], height[stk.top()]) - height[mid]) * (i - stk.top() - 1),分别是高乘宽。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> stk;
        int res = 0;

        for (int i = 0; i < height.size(); ++i) {
            while (!stk.empty() && height[i] > height[stk.top()]) {
                int mid = stk.top();
                stk.pop();
                if (!stk.empty()) res += (min(height[i], height[stk.top()]) - height[mid]) * (i - stk.top() - 1);
            }
            stk.push(i);
        }
        return res;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


84h. 柱状图中最大的矩形

题目链接
代码随想录文章讲解链接

方法一:三次遍历

用时:18m4s

思路

以某个柱子为基准,最大矩形面积与该柱子两侧第一个比它矮的柱子的位置有关。
前两次遍历找到每个柱子左右两侧第一个比它矮的柱子的位置。
最后一次遍历计算以各个柱子为基准的最大矩形面积,最大值即为答案。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int size = heights.size();
        vector<int> leftMin(size);
        vector<int> rightMin(size);
        int res = 0;

        // 记录每个柱子左边第一个比它小的柱子的位置
        leftMin[0] = -1;
        for (int i = 1; i < size; ++i) {
            int left = i - 1;
            while (left >= 0 && heights[left] >= heights[i]) left = leftMin[left];
            leftMin[i] = left;
        }
        // 记录每个柱子右边第一个比它小的柱子的位置
        rightMin[size - 1] = size;
        for (int i = size - 2; i >= 0; --i) {
            int right = i + 1;
            while (right < size && heights[right] >= heights[i]) right = rightMin[right];
            rightMin[i] = right;
        }
        // 遍历以每个柱子为基准的矩形大小,记录最大值
        for (int i = 0; i < size; ++i) res = max(res, heights[i] * (rightMin[i] - leftMin[i] - 1));
        return res;
    }
};

方法二:单调栈

用时:33m9s

思路

因为我们要找到某个基准柱子左右两边比它小的柱子的位置,所以药维护一个栈底到栈顶单调递增的单调栈,这样对于栈顶元素的柱子,它左边第一个比它小的柱子就是第二个栈顶元素,右边第一个比它小的元素就是遍历过程中比栈顶元素小的元素。
遍历数组,若元素大于等于栈顶元素,则入栈;若元素小于栈顶元素,则取出栈顶元素作为基准柱子,然后弹出栈顶元素,基准柱子左边第一个比它小的柱子就是此时的栈顶元素,右边第一个比它小的柱子就是当前遍历的元素,然后记录矩形的面积并更新答案。
由于在遍历的过程中,可能会出现栈为空的情况,以及数组本身就是递增数组的情况,此时会有特殊情况需要处理,可以在数组前后各加入一个0,简化逻辑,因为0一定是小于柱子高度,能够作为左右两端最矮的基准柱子的边界。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> stk;
        int res = 0;

        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        stk.push(0);
        for (int i = 1; i < heights.size(); ++i) {
            while (heights[i] < heights[stk.top()]) {
                int mid = stk.top();
                stk.pop();
                res = max(res, heights[mid] * (i - stk.top() - 1));
            }
            stk.push(i);
        }
        return max(res, heights[stk.top()]);
    }
};

看完讲解的思考

无。

代码实现遇到的问题

边界问题处理了半天没搞定,在数组前后各加入一个0的方法真巧妙。


最后的碎碎念

最近都在搞比赛,好久没刷题了,比赛目前搞得差不多了,得接着刷题了。
希望比赛能拿个好成绩,求求求求求求了!

你可能感兴趣的:(代码随想录,leetcode,算法,职场和发展,c++)