美文网首页
417. 太平洋大西洋水流问题(Python)

417. 太平洋大西洋水流问题(Python)

作者: 玖月晴 | 来源:发表于2020-09-24 16:41 被阅读0次

    题目

    难度:★★★☆☆
    类型:二维数组
    方法:深度优先搜索

    力扣链接请移步本题传送门
    更多力扣中等题的解决方案请移步力扣中等题目录

    给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。

    规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。

    请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。

    提示:

    输出坐标的顺序不重要
    m 和 n 都小于150

    示例

    给定下面的 5x5 矩阵:

    太平洋 ~ ~ ~ ~ ~
    ~ 1 2 2 3 (5) *
    ~ 3 2 3 (4) (4) *
    ~ 2 4 (5) 3 1 *
    ~ (6) (7) 1 4 5 *
    ~ (5) 1 1 2 4 *
    * * * * * 大西洋

    返回:

    [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).

    解答

    方格问题常常可以使用深度优先搜索实现。这个问题我们最好采用逆向思维,俗话说,水往低处流,能够流向太平洋和大西洋的点,恐怕是最后被两大洋淹没的,例如电影2012中的珠峰。问题就转化成了,如果世界末日来临,海水上涨,哪些点是可以被最后淹没的。这里为了便于大家理解,把点方格和大陆都做了实例化。

    相关实例和方法:
    【点】:获取点的位置,获取相邻的点;
    【方格】:获取方格中某点的值,设置方格中某点的值,判断点是否在方格内;
    【大陆】:包含三个主要的实例变量,即每个点的海拔,先被太平洋淹没的点的网格和先被大西洋淹没的点的网格,我们称为太平洋占领区和大西洋占领区,后面的两个方格,是布尔类型的,用于表示太平洋或大西洋上涨后哪些点会被淹没掉,暂且认为太平洋和大西洋是分隔开的。

    如何进行深度优先搜索?首先我们应该搞清楚在本任务中深度优先搜索的意义在哪里。以太平洋为例,海水上涨后,海拔低的点是要优先被淹没的,海水从海陆边界那些点出发,开始蔓延到内陆,每当淹没一个点之后,就需要考察该点周围的四个点的海拔与当前点的海拔之间的关系,如果高于获得等于当前点,则继续淹没,否则停止淹没,这样保证水流是一直向上的,才能找到山顶。

    深度优先搜索完成后,面对左上角一堆True的太平洋占领区和右下角一堆True的大西洋占领区,如何确定山顶的坐标?其实两个方格对应位置做与就可以了,这些点也就可以满足,水流既可以到太平洋,也可以到大西洋。

    class Point:
        """
        点的实例,包含获取左边、右边、上边、下边相邻点和获取当前坐标值的方法。
        """
        def __init__(self, h, w):
            self.h = h
            self.w = w
    
        @property
        def left(self):
            return Point(self.h, self.w-1)
    
        @property
        def right(self):
            return Point(self.h, self.w+1)
    
        @property
        def upper(self):
            return Point(self.h-1, self.w)
    
        @property
        def lower(self):
            return Point(self.h+1, self.w)
    
        @property
        def locate(self):
            return [self.h, self.w]
    
    
    class Board:
        """
        网格实例,用于构建网格,包含取某点值,设置某点值,判断点是否在网格内等方法。
        """
        def __init__(self, value):
    
            value = value if value else [[]]
            self.value = value
            self.height = len(value)
            self.width = len(value[0])
    
        def get(self, point):
            assert isinstance(point, Point)
            if self.is_valid(point):
                return self.value[point.h][point.w]
            return -1
    
        def set(self, point, value):
            assert isinstance(point, Point)
            if self.is_valid(point):
                self.value[point.h][point.w] = value
                return True
            return -1
    
        def is_valid(self, point):
            assert isinstance(point, Point)
            return 0 <= point.w < self.width and 0 <= point.h < self.height
    
    
    class MainLand:
        """
        陆地实例。包含淹没太平洋,淹没大西洋,获取山顶坐标等方法。
        """
        def __init__(self, value):
    
            self.land = Board(value)
            self.width = self.land.width
            self.height = self.land.height
            self.pacific = Board([[False for _ in range(self.width)] for _ in range(self.height)])      # 太平洋淹没的陆地
            self.atlantic = Board([[False for _ in range(self.width)] for _ in range(self.height)])     # 大西洋淹没的陆地
    
        def submerge_atlantic(self, point):
            """
            太平洋淹没该陆地
            :param point:
            :return:
            """
            assert isinstance(point, Point)
            self.atlantic.set(point, True)
    
            def submerge(p):
                if self.atlantic.get(p) is False and self.land.get(p) >= self.land.get(point):
                    self.submerge_atlantic(p)
    
            submerge(point.left)
            submerge(point.right)
            submerge(point.upper)
            submerge(point.lower)
    
        def submerge_pacific(self, point):
            """
            大西洋淹没该陆地
            :param point:
            :return:
            """
            assert isinstance(point, Point)
            self.pacific.set(point, True)
    
            def submerge(p):
                if self.pacific.get(p) is False and self.land.get(p) >= self.land.get(point):
                    self.submerge_pacific(p)
    
            submerge(point.left)
            submerge(point.right)
            submerge(point.upper)
            submerge(point.lower)
    
        def submerge_all(self):
    
            pacific_boarders = [Point(0, j) for j in range(self.width)] + [Point(i, 0) for i in range(self.height)]
            atlantic_boarders = [Point(self.height-1, j) for j in range(self.width)] + [Point(i, self.width-1) for i in range(self.height)]
    
            for p in pacific_boarders:
                self.submerge_pacific(p)
    
            for p in atlantic_boarders:
                self.submerge_atlantic(p)
    
        @property
        def get_peak(self):
            """
            根据太平洋和大西洋淹没的陆地交集,获得山顶坐标。
            :return:
            """
            results = []
            for i in range(self.height):
                for j in range(self.width):
                    point = Point(i, j)
                    if self.pacific.get(point) and self.atlantic.get(point):
                        results.append(point.locate)
            return results
    
    
    class Solution:
        def pacificAtlantic(self, matrix):
            mainland = MainLand(matrix)
            mainland.submerge_all()
            # return mainland.
            peak_list = mainland.get_peak
            return peak_list
    
    
    if __name__ == "__main__":
        matrix = [[1, 2, 2, 3, 5],
                  [3, 2, 3, 4, 4],
                  [2, 4, 5, 3, 1],
                  [6, 7, 1, 4, 5],
                  [5, 1, 1, 2, 4],
                  ]
        s = Solution()
        res = s.pacificAtlantic(matrix)
        print(res)
    

    以题目为例,海拔方格,太平洋占领区和大西洋占领区分别为:

    海拔:
    [[1, 2, 2, 3, 5],
     [3, 2, 3, 4, 4],
     [2, 4, 5, 3, 1],
     [6, 7, 1, 4, 5],
     [5, 1, 1, 2, 4],
    ]
    太平洋占领区:
    [[True, True, True, True, True],
     [True, True, True, True, True],
     [True, True, True, False, False],
     [True, True, False, False, False],
     [True, False, False, False, False]]
    大西洋占领区:
    [[False, False, False, False, True],
     [False, False, False, True, True],
     [False, False, True, True, True],
     [True, True, True, True, True],
     [True, True, True, True, True]]
    

    如有疑问或建议,欢迎评论区留言~

    有关更多力扣中等题的python解决方案,请移步力扣中等题解析

    相关文章

      网友评论

          本文标题:417. 太平洋大西洋水流问题(Python)

          本文链接:https://www.haomeiwen.com/subject/wcttuktx.html