Day 19 拓展:42|407. 接雨水I II, 11. 盛最多水容器

42. 接雨水

  • 思路
    • example
    • 木桶效应,短板效应
    • 每个格子左右两边最大值的短板(h), h - height[i] if this is \geq 0
    • 解法1:暴力
      • 复杂度. 时间:O(n^2), 空间: O(1)
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        res = 0
        for i in range(n):
            leftMax = 0
            for j in range(0, i):
                leftMax = max(leftMax, height[j])
            rightMax = 0
            for j in range(i+1, n):
                rightMax = max(rightMax, height[j])
            if min(leftMax, rightMax) > height[i]:
                res += min(leftMax, rightMax) - height[i]
        return res
  • 解法2:动规 (DP)
    • 维护leftMax (-->),rightMax数组 (<--)
    • leftMax[i]: max of height[0], ..., height[i-1]
    • rightMax[i]: max of height[i+1], ..., height[n-1]
      • 复杂度. 时间:O(n), 空间: O(n)
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        leftMax = [0] * n
        rightMax = [0] * n
        for i in range(1, n):
            leftMax[i] = max(leftMax[i-1], height[i-1])
        for i in range(n-2, -1, -1):
            rightMax[i] = max(rightMax[i+1], height[i+1])
        res = 0
        for i in range(n):
            h = min(leftMax[i], rightMax[i])
            if h > height[i]:
                res += h - height[i]
        return res
  • 解法3:双指针: left, right. -->*<--
    • 指针移动规则?
      • 给定left, right (left <= right), 希望能够确定left 和 right其中一个位置的水位 (所能容纳的水量)。
      • 可得到left之前(不包括left) 最大高度,以及right之后最大高度
        • 假设height[left-1] < height[right+1], 则left这个位置的水位必然由leftMax[left]决定 (这个位置的储水不可能从右边界流出去), 从而可以确定left这个位置的水位:max(0, leftMax[left] - height[left])
          • 下一步:left += 1
        • 假设height[left -1] >= height[right+1], ...., 可以由rightMax[right]确定right这个位置的水位
          • 下一步:right -= 1
    • 上面的过程可以只维护当前的leftMax和rightMax 这两个数值。
    • 复杂度. 时间:O(n), 空间: O(1)
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        if n <= 2:
            return 0
        left, right = 1, n-2 
        leftMax, rightMax = height[0], height[n-1]
        res = 0
        while left <= right:
            if height[left-1] < height[right+1]:
                leftMax = max(leftMax, height[left-1])
                res += max(0, leftMax - height[left])
                left += 1
            else:
                rightMax = max(rightMax, height[right+1])
                res += max(0, rightMax - height[right])
                right -= 1
        return res
  • 解法四:优先队列 heapq (size = 2)
    • que: 最小堆, 初始化存储第一个和最后一个 (高度,index)
    • 从外往内遍历“填充”水位(因为水一定是从左右两个边界溢出),得用que,每次pop que 首位(heapq.heappop(que)) (左右边界中的最小高度---短板效应),然后判断该高度对应Index的邻居的水位。更新res, 更新新的边界入最小堆。
    • 可以维护一个visited数组,确保不会重复访问。
    • 复杂度. 时间:O(n), 空间: O(1)
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        if n <= 2:
            return 0
        que = []
        heapq.heappush(que, (height[0], 0))
        heapq.heappush(que, (height[n-1], n-1))
        visited = [False] * n
        visited[0] = visited[n-1] = True
        direction = [-1, 1]
        res = 0
        while que:
            min_height, min_index = heapq.heappop(que)
            for i in direction:
                index = min_index + i 
                if index >= 0 and index <= n-1 and visited[index] == False:
                    min_height_new = max(min_height, height[index])
                    res += min_height_new - height[index]
                    visited[index] = True
                    heapq.heappush(que, (min_height_new, index))
        return res

407. 接雨水 II

  • 思路
    • example
    • 接雨水 高维版本
    • 由外身内遍历边界 (水一定是从外边界溢出)
      • 优先队列 (最小堆 heapq)
      • directions方向向量: 方便考察最小边界周围点的水位
      • visited数组避免重复访问
        • 判断visited[x][y]时先检查x,y是否越界。
    • 复杂度. 时间:O(mn), 空间: O(m+n)
class Solution:
    def trapRainWater(self, heightMap: List[List[int]]) -> int:
        m, n = len(heightMap), len(heightMap[0])
        if m <= 2 or n <= 2:
            return 0
        res = 0
        que = []
        visited = [[False]*n for _ in range(m)]
        directions = [(-1,0), (1,0), (0,-1), (0,1)]
        for j in range(n):
            heapq.heappush(que, (heightMap[0][j], (0,j)))
            visited[0][j] = True
            if m - 1 > 0:
                heapq.heappush(que, (heightMap[m-1][j], (m-1,j)))
                visited[m-1][j] = True
        for i in range(1, m-1):
            heapq.heappush(que, (heightMap[i][0], (i,0)))
            visited[i][0] = True
            if n -1 > 0:
                heapq.heappush(que, (heightMap[i][n-1], (i,n-1)))
                visited[i][n-1] = True
        while que:
            min_height, coordinate = heapq.heappop(que)
            x0, y0 = coordinate[0], coordinate[1]
            for direction in directions:
                dx, dy = direction[0], direction[1]
                x, y = x0 + dx, y0 + dy
                if 0<=x<m and 0<=y<n and visited[x][y] == False:
                    min_height_new = max(min_height, heightMap[x][y])
                    res += min_height_new - heightMap[x][y]
                    visited[x][y] = True 
                    heapq.heappush(que, (min_height_new, (x,y)))
        return res 

11. 盛最多水的容器

  • 思路
    • example
    • 短板效应
      • [left, right]: 储水量 = min(height[left], height[right]) * (right - left)
    • 解法1:暴办法
      • 复杂度. 时间:O(n^2), 空间: O(1)
class Solution:
    def maxArea(self, height: List[int]) -> int:
        n = len(height)
        res = 0
        for left in range(n):
            for right in range(left+1, n):
                res = max(res, min(height[left], height[right]) * (right - left))
        return res
  • 解法2:双指针, -->*<--
    • left, right = 0, n-1
    • 在更新完[left, right]结果后,考虑left += 1, 或者right -= 1
    • 如果height[left] < height[right]: 考虑left += 1, 这样在宽度减小的情况下,min_height有可能增大;否则如果right-=1, min_height <= height[left],不可能改进结果。
    • 复杂度. 时间:O(n), 空间: O(1)
class Solution:
    def maxArea(self, height: List[int]) -> int:
        n = len(height)
        left, right = 0, n-1
        res = 0
        while left < right:
            res = max(res, min(height[left], height[right])*(right-left))
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return res
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容