• 第三周LeetCode记录


    9.20 13.最大矩形

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

    示例:

    输入:
    [
      ["1","0","1","0","0"],
      ["1","0","1","1","1"],
      ["1","1","1","1","1"],
      ["1","0","0","1","0"]
    ]
    输出: 6
    

    思路

    两次遍历,第一次最大元素个数,第二次逐行遍历

    我的解

    时间复杂度过高

    最优解一

    class Solution:
    
        def maximalRectangle(self, matrix: List[List[str]]) -> int:
            if not matrix: return 0
    
            m = len(matrix)  
            n = len(matrix[0])
    
            left = [0] * n # initialize left as the leftmost boundary possible
            right = [n] * n # initialize right as the rightmost boundary possible
            height = [0] * n
    
            maxarea = 0
    
            for i in range(m):
    
                cur_left, cur_right = 0, n
                # update height
                for j in range(n):
                    if matrix[i][j] == '1': height[j] += 1
                    else: height[j] = 0
                # update left
                for j in range(n):
                    if matrix[i][j] == '1': left[j] = max(left[j], cur_left)
                    else:
                        left[j] = 0
                        cur_left = j + 1
                # update right
                for j in range(n-1, -1, -1):
                    if matrix[i][j] == '1': right[j] = min(right[j], cur_right)
                    else:
                        right[j] = n
                        cur_right = j
                # update the area
                for j in range(n):
                    maxarea = max(maxarea, height[j] * (right[j] - left[j]))
    
            return maxarea
    
    

    问题

    Q:为什么所有的right都要从5开始。所有的left从0开始

    A: 如果是[1,0,0],left[0,0,0],right[2,3,3],如果右边遇到了0,则说明碰到了有边界,同上方的右边界相比,谁小取谁。如果左边遇到了0,和上方的左边界相比,谁大取谁。因为上方的边界包含了上部所有的,所以边界一定是矩形的边界。每次比较的时候是拿上一次的同列的结果,去和当前列的坐标相比,所以右边取最大(可以用min取出右边最小坐标),左边取最小(用max取出左边最大坐标)

    总结

    是对点的遍历,每个点取最大的矩形计算,每个点可以引用上一个点的结果。

    9.22 14. 柱状图中最大矩形

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

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

    输入: [2,1,5,6,2,3]
    输出: 10
    

    思路

    暴力破解,从左到右,自上而下,分别求出每个高度可以得到的最大矩形。

    我的解

    class Solution:
        @classmethod
        def largestRectangleArea(self, heights:list) -> int:
    
            list_len = len(heights)
            if list_len==1:
                return heights[0]
    
     
            area = 0
            # 遍历列表起始坐标
            for index in range(list_len):
                max_num = heights[index]
                # 高度
                for i in range(1,max_num+1):
                    # 当前坐标
                    for con in range(index,list_len):
                        # 比较高度
                        if i > heights[con]:
                            area = max((con-index)*i,area)
                            break
                        if con == list_len -1:
                            area = max((list_len - index) * i,area)
                            
            
            return area
    
    if __name__ == "__main__":
        res = Solution.largestRectangleArea([0,0,0,0,0,0,0,0,2147483647])
        print(res)
    

    最优解

    class Solution:
        @classmethod
        def largestRectangleArea(self, heights: list) -> int:
            if len(heights) == 0: return 0
            if len(heights) == 1: return heights[-1]
    
            n = len(heights)
    
            stack = list()
    
            area = 0
            for i in range(n):
                # 当栈里有元素,且大于添加的数时
                while stack and heights[stack[-1]] > heights[i]:
                    # 记录高度
                    a = stack.pop()
                    height = heights[a]
    
                    # 如果最后一个元素高度和之前一样继续弹出
                    while stack and heights[stack[-1]] == height:
                        stack.pop()
    
                    # 栈顶元素确定的宽度,如果栈为空,则说明添加的元素最矮,可以延伸到左边届
                    if len(stack)==0:
                        width = i
                    # 如果栈不为空
                    else:
                    		# i-1是当前高度对应的下标
                        width = i - stack[-1] - 1
                    area = max(area,width*height)
                stack.append(i)
    
            # 当遍历完成后,栈里还有元素,添加的元素递增或相等
            while stack:
                # 记录高度
                a = stack.pop()
                height = heights[a]
    
                # 如果最后一个元素高度和之前一样继续弹出
                while stack and heights[stack[-1]] == height:
                    stack.pop()
    
                # 重要:无论栈是否为空,当前元素一定可以扩散到最右边
                if len(stack) == 0:
                    width = n
                # 如果栈不为空
                else:
                    width = n - stack[-1] - 1
                area = max(area, width * height)
    
            return area
    

    优化:哨兵模式

        def largestRectangleArea(self, heights: list) -> int:
            import copy
            if len(heights) == 0: return 0
            if len(heights) == 1: return heights[-1]
    
            
    
            stack = list()
            stack.append(0)
    
            new_heights = copy.deepcopy(heights)
            new_heights.insert(0,0)
            new_heights.append(0)
    
            heights = new_heights
            n = len(heights)
    
            area = 0
            for i in range(1,n):
                # 当栈里有元素,且大于添加的数时
                while heights[stack[-1]] > heights[i]:
                    # 记录高度
                    a = stack.pop()
                    height = heights[a]
    
                    # 如果最后一个元素高度和之前一样继续弹出
                    while heights[stack[-1]] == height:
                        stack.pop()
    
      
                    width = i - stack[-1] - 1
                    area = max(area,width*height)
                stack.append(i)
    
            return area
    

    总结

    用栈结构存储了上一次的信息。

    1. 什么时候会弹栈和停止弹栈:当遍历到的高度小于最后一个元素时,说明矩形达到边界,弹栈依次计算。直至元素小于遍历到的高度,说明达到左边届。
    2. 弹出时候栈为空是什么状态:说明遍历的高度最矮,是最小的高度。
    3. 弹出时遇到为0,栈还可以为空吗:如果列表中包含0,非0则不可能把0弹出去。如果0弹0,高度是0计算出来也是0,没有影响。
    4. 遍历完成后,栈内元素的宽度怎么算:当遍历完成后,栈中至少有一个元素,即最小,左右边界都达到,说明宽度为数组长度。如果pop得到高度不为空,右边界还是取到。总之,栈内元素都可以达到右边界。
    5. 哨兵模式:新增一个首元素为0,这样就不会空栈,尾元素为0,就会弹栈计算面积最大值。
    • 单调栈

      栈内元素维持了单调性的场景

      1. 单调递增栈可以找到左边第一个比当前出栈元素小的元素
      2. 单调递减栈可以找到左边第一个比当前出栈元素大的元素

    9.24 15. 除法求值

    给出方程式 A / B = k, 其中 A 和 B 均为用字符串表示的变量, k 是一个浮点型数字。根据已知方程式求解问题,并返回计算结果。如果结果不存在,则返回 -1.0。

    示例 :

    给定 a / b = 2.0, b / c = 3.0
    问题: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? 
    返回 [6.0, 0.5, -1.0, 1.0, -1.0 ]
    

    思路

    对于给定的两个列表,求交集,把变量统一。

    我的解

    解法过于笨重,要分情况讨论交集为0,1,2三种情况。要根据交集判断是除数还是被除数,如果是只有一个交集,判断是否为(a,a),(a,b)还是(a,b),(a,c),判断很繁琐。

    最优解

        def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
            # 构造图,equations的第一项除以第二项等于value里的对应值,第二项除以第一项等于其倒数
            graph = {}
            for (x, y), v in zip(equations, values):
                if x in graph:
                    graph[x][y] = v
                else:
                    graph[x] = {y: v}
                if y in graph:
                    graph[y][x] = 1/v
                else:
                    graph[y] = {x: 1/v}
            
            # dfs找寻从s到t的路径并返回结果叠乘后的边权重即结果
            def dfs(s, t) -> int:
                if s not in graph:
                    return -1
                if t == s:
                    return 1
                for node in graph[s].keys():
                    if node == t:
                        return graph[s][node]
                    elif node not in visited:
                        visited.add(node)  # 添加到已访问避免重复遍历
                        v = dfs(node, t)
                        if v != -1:
                            return graph[s][node]*v
                return -1
    
            # 逐个计算query的值
            res = []
            for qs, qt in queries:
                visited = set()
                res.append(dfs(qs, qt))
            return res
    
    

    总结:

    图解法和dfs,两点之间的关系用图中的边的关系对应。可以用相邻的点来连接。溯源来深度遍历所有的节点。

  • 相关阅读:
    java 和.net 开发平台的感受(菜鸟级)
    结构体应用统计学生成绩
    实验十 链表
    绘制抛物线(带比例缩放)
    上下三角矩阵的输出
    结构体应用分类与索引
    笔试题之数据库
    动态规划求回文给定字符串,插入字符形成回文
    三行九个点,用4条线段连接(扩展,用3条,用1条)
    名言记录
  • 原文地址:https://www.cnblogs.com/jimmyhe/p/13742044.html
Copyright © 2020-2023  润新知