代码随想录 day51 单调栈 接雨水 + 柱状图中的最大面积

42. 接雨水

力扣题目链接
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2:
输入:height = [4,2,0,3,2,5]
输出:9

暴力解法

from typing import List


# 暴力解法(leetcode超时)
class Solution:
    def trap(self, height: List[int]) -> int:
        # 按照列来计算体积
        n = len(height)
        if n <= 2: return 0
        result = 0
        # i = 0, n-1, 开始和最后位置无法积水
        for i in range(1, n-1):
            lHeight = height[i]
            rHeight = height[i]

            # 左边
            for j in range(i-1, -1, -1):
                if lHeight < height[j]:
                    lHeight = height[j]

            # 右边
            for j in range(i+1, n):
                if rHeight < height[j]:
                    rHeight = height[j]
            h = min(lHeight, rHeight) - height[i]   # 左侧 右侧高度----你需要什么
            print(height[:i], height[i], height[i+1:])
            print(i, height[i], lHeight, rHeight,h)
            print('\n')
            if h > 0:
                result += h
        return result

# height = [0,1,0,2,1,0,1,3,2,1,2,1]
# c = Solution().trap(height)

双指针

# 双指针
class Solution:
    def trap(self, height: List[int]) -> int:
        #  按照列来计算体积
        n = len(height)
        if n <= 2: return 0
        result = 0
        # i = 0, n-1, 开始和最后位置无法积水
        max_left_height = [0 for _ in range(n)]
        max_right_height = [0 for _ in range(n)]

        max_left_height[0] = height[0]
        for i in range(1, n):
            max_left_height[i] = max(max_left_height[i - 1], height[i])

        max_right_height[n - 1] = height[n - 1]  ## 防止右边溢出
        for i in range(n - 2, -1, -1):
            max_right_height[i] = max(max_right_height[i + 1], height[i])

        for i in range(1, n - 1):
            h = min(max_left_height[i], max_right_height[i]) - height[i]
            print(i, height[:i], height[i], height[i + 1:])
            print(max_left_height[i], max_right_height[i], h)
            if h > 0: result += h
        return result

模拟过程

[0, 1, 0, 2, 2, 1, 0, 1, 3, 2, 1, 2, 1]
————————————————————————————————————————————
0
————————————————————————————————————————————
开始和结束无法积水
i= 1, height[1] > height[stack[-1]], stack.pop(), stack.append(i)-- 还要待考虑
————————————————————————————————————————————
1
————————————————————————————————————————————

i=2,height[2]=0 < height[stack[-1]] stack.append(i)
————————————————————————————————————————————
1 2
————————————————————————————————————————————

开始和结束无法积水
i= 3, height[3]=2 > height[stack[-1]]=0, mid = stack.pop(), left = stack[-1], width = i - stack[-1] - 1, h = min(height[stack[-1]], height[i]) - height[i]
if h >0 : res += h

i= 3, height[3]=2 > height[stack[-1]]=0, mid = stack.pop() = 2, left = stack[-1]=1, width = i - stack[-1] - 1 = 3-1-1=1, h = min(height[stack[-1]], height[i]) - height[mid] = min(1, 2) - 0 = 1

————————————————————————————————————————————
1
————————————————————————————————————————————

if mid = stack.pop() = 1, 则没有left = stack[-1] 会报错
所以对于上面的计算需要有前提
while stack and height[i] > height[stack[-1]]:
    mid = stack.pop()
    if stack:
        left = stack[-1]
        width = i - left - 1
        heighty = min(height[left], height[i]) - height[mid]
        res += width * heighty
stack.append(i)
————————————————————————————————————————————
3
————————————————————————————————————————————
i = 4, height[4] = 2 = height[stack[-1]], 此时应该把第一个 2 取出,使用右边 2 高度进行接下来的统计
————————————————————————————————————————————
4
————————————————————————————————————————————
 ## [0, 1, 0, 2, 2, 1, 0, 1, 3, 2, 1, 2, 1]
i = 5, height[5] = 1 <  height[stack[-1]], 加入
if height[i] < height[stack[-1]]: stack.append(i)
————————————————————————————————————————————
4 5
————————————————————————————————————————————

i = 6, height[5] = 0 <  height[stack[-1]], 加入
if height[i] < height[stack[-1]]: stack.append(i)
————————————————————————————————————————————
4 5 6
————————————————————————————————————————————
i = 7, height[7] = 1 >  height[stack[-1]],
if mid = stack.pop() = 1, 则没有left = stack[-1] 会报错
所以对于上面的计算需要有前提
while stack and height[i] > height[stack[-1]]:
    mid = stack.pop()
    if stack:
        left = stack[-1]
        width = i - left - 1
        heighty = min(height[left], height[i]) - height[mid]
        res += width * heighty
stack.append(i)
————————————————————————————————————————————
4 5
————————————————————————————————————————————
mid = 6, left = 5, width = 7 - 5-1 = 1, heighty=min(1,1)-0=1; res +=1
————————————————————————————————————————————
4 5
————————————————————————————————————————————
 ## [0, 1, 0, 2, 2, 1, 0, 1, 3, 2, 1, 2, 1]
mid = 5 , left = 4, width=7-4-1=2, height=min(2,1)-1=0, res +=0
————————————————————————————————————————————
4
————————————————————————————————————————————
mid = 4, 没有left, stop, 加入i
————————————————————————————————————————————

————————————————————————————————————————————
加入i
————————————————————————————————————————————
7
————————————————————————————————————————————
 ## [0, 1, 0, 2, 2, 1, 0, 1, 3, 2, 1, 2, 1]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
i=8
while stack and height[i] > height[stack[-1]]:
    mid = stack.pop()
    if stack:
        left = stack[-1]
        width = i - left - 1
        heighty = min(height[left], height[i]) - height[mid]
        res += width * heighty
stack.append(i)

mid = stack.pop() = 7, left = 没有, 加入 i
————————————————————————————————————————————

————————————————————————————————————————————
加入i
————————————————————————————————————————————
8
————————————————————————————————————————————
i = 9 ,val=2 < height[stack[-1]]=3, 加入i
加入i
————————————————————————————————————————————
8 9
————————————————————————————————————————————
i = 10 ,val=1 < height[stack[-1]]=2, 加入i
加入i
————————————————————————————————————————————
8 9 10
————————————————————————————————————————————
## [0, 1, 0, 2, 2, 1, 0, 1, 3, 2, 1, 2, 1]
   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
i = 11
while stack and height[i] > height[stack[-1]]:
    mid = stack.pop()
    if stack:
        left = stack[-1]
        width = i - left - 1
        heighty = min(height[left], height[i]) - height[mid]
        res += width * heighty
stack.append(i)
————————————————————————————————————————————
8 9
————————————————————————————————————————————
mid = 10, left = 9, width = i - left - 1 = 11-9-1 = 1, heighty=min(2, 2)-height[mid]=2-1=1, h=1*1=1

————————————————————————————————————————————
8
————————————————————————————————————————————
mid = 9, left = 8, width = xxx

mid = 8, left = '没有',

————————————————————————————————————————————

————————————————————————————————————————————
————————————————————————————————————————————
11
————————————————————————————————————————————

i= 12, < tack[-1]对应的值, stop。

单调栈

class Solution:
    def trap(self, height: List[int]) -> int:
        result = 0
        stack = [0]
        n = len(height)
        for i in range(1, n):
            if height[i] < height[stack[-1]]:
                stack.append(i)
                print('if <', stack)
            elif height[i] == height[stack[-1]]:
                stack.pop()
                stack.append(i)
                print('elif ==', stack)
            else:
                print(i, stack[-1])
                while stack and height[i] > height[stack[-1]]:
                    print('1 else stack', stack)
                    mid = stack.pop()
                    print('xx')
                    if stack:
                        print('else, stack.pop()', stack, mid, stack[-1])
                        left = stack[-1]
                        width = i - left - 1
                        heighty = min(height[left], height[i]) - height[mid]
                        result += width * heighty
                        print(width * heighty,'hh')
                stack.append(i)
                print('1 else stack add', stack)
        return result



# height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 2, 1, 2, 1]
# index =  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
height=[3, 2, 1, 2, 3]
c = Solution().trap(height)

84.柱状图中最大的矩形

力扣题目链接

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

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

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

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

1 <= heights.length <=10^5
0 <= heights[i] <= 10^4

思路


从我自己出发, 找左边第一个小于heights[i]的位置
右边第一个小于heights[i]的位置, 面积的width = right - left - 1

之后面积 = width * heights[i]

一个一个的找。就能找到最大的面积。

from typing import List


class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        stack = [-1]
        n = len(heights)
        area = 0
        for i in range(0, n):
            if heights[i] > heights[stack[-1]]:
                stack.append(i)
            if heights[i] == heights[stack[-1]]:
                stack.pop()
                stack.append(i)
            else:
                while len(stack) >= 2 and heights[i] < heights[stack[-1]]:
                    mid = stack.pop()
                    right = i
                    left = stack[-1]
                    area = max(area, (right - left - 1) * heights[mid])
                stack.append(i)
        while len(stack) >= 2:
            mid = stack.pop()
            right = n
            left = stack[-1]
            area = max(area, (right - left - 1) * heights[mid])
        return area

heights = [2,1,5,6,2,3]
c = Solution().largestRectangleArea(heights)

84.柱状图中最大的矩形

力扣题目链接

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

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

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

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

1 <= heights.length <=10^5
0 <= heights[i] <= 10^4

思路


从我自己出发, 找左边第一个小于heights[i]的位置
右边第一个小于heights[i]的位置, 面积的width = right - left - 1

之后面积 = width * heights[i]

一个一个的找。就能找到最大的面积。

from typing import List

## code python 单调栈
```py
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        stack = [-1]
        n = len(heights)
        area = 0
        for i in range(0, n):
            if heights[i] > heights[stack[-1]]:
                stack.append(i)
            if heights[i] == heights[stack[-1]]:
                stack.pop()
                stack.append(i)
            else:
                while len(stack) >= 2 and heights[i] < heights[stack[-1]]:
                    mid = stack.pop()
                    right = i
                    left = stack[-1]
                    area = max(area, (right - left - 1) * heights[mid])
                stack.append(i)
        while len(stack) >= 2:
            mid = stack.pop()
            right = n
            left = stack[-1]
            area = max(area, (right - left - 1) * heights[mid])
        return area

heights = [2,1,5,6,2,3]
c = Solution().largestRectangleArea(heights)

## code python 单调栈精简
```py
# 单调栈精简
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        heights.insert(0, 0)
        heights.append(0)
        stack = [0]
        result = 0
        for i in range(1, len(heights)):
            while stack and heights[i] < heights[stack[-1]]:
                mid_height = heights[stack[-1]]
                stack.pop()
                if stack:
                    # area = width * height
                    area = (i - stack[-1] - 1) * mid_height
                    result = max(area, result)
            stack.append(i)
        return result
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值