接雨水算法题实现

一维接雨水算法题实现

https://leetcode-cn.com/problems/trapping-rain-water/

 


def trap_rain_water(height):
    # 思路: 一个格子能不能接到雨水,能接到多少雨水,由其两边最高的"墙"决定
    # 从第二个位置遍历每个格子,遍历到倒数第二个,找到每个格子两边最高的墙
    # 格子高于等于墙高则无法接住雨水,如果比墙低,则能接住较低的墙减去格子高度的雨水
    # 将每个格子接到的雨水加起来,遍历完成后即为总的雨水量

    if not height:
        return 0

    rain_water_count = 0
    left_max = height[0]
    right_max = max(height[1:])
    for index, high in enumerate(height[1: -1], 1):
        if left_max < high:
            left_max = high

            if high == right_max:
                right_max = max(height[index + 1:])

            continue

        if high == right_max:
            right_max = max(height[index + 1:])
            continue

        if left_max > high and right_max > high:
            lower_wall = left_max if left_max < right_max else right_max
            rain_water_count += lower_wall - high
    return rain_water_count


if __name__ == '__main__':
    ret = trap_rain_water2([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])
    print(ret)
    ret = trap_rain_water([4, 2, 0, 3, 2, 5])
    print(ret)

 

二维接雨水算法实现

https://leetcode-cn.com/problems/trapping-rain-water-ii/submissions/

思路1,正向思路

  • 最外圈格子一定接不到雨水,可将最外圈看着围墙,所有从内圈开始遍历每个格子
  • 遍历到格子A时,查看其四个方向上的高度是否高于A的高度,如果第一个方向高于A,则这个方向遍历完并将高度记录下来
  • 如果第二个方向比A低或高度相等,则判定第二个方向是否为边界,如果是边界则格子A定不能接到水,将格子A标记为核对完成
  • 如果第二个方向比A低或高度相等,且不为边界,则从第二个方向的格子B想剩余的三个方向比较(因其中的一个方向是A,不能倒回去比较)
  • 重复上诉两部,直到遍历到能确认格子A能不能接到水
  • A不能接到水的,则A遍历过的足迹上,所有高于等于A的格子一定不能接到水,将之全部标记为核对完成
  • A能接到水的,计算A接到的水量,A遍历过的足迹上所有第二等于A的都能接到水并计算水量
  • 遍历完成所有内圈格子后,核对有没有格子接到水,如果没有则遍历完成,如果有则继续第二次遍历,后续的遍历可直接跳过核对完成的格子
class Solution(object):

    def createFullStateMap(self, heightMap):
        full_state_map = []
        for row in heightMap:
            full_state_map.append([False] * len(row))

        first_row = full_state_map[0]
        for i, _ in enumerate(first_row):
            first_row[i] = True

        last_row = full_state_map[-1]
        for i, _ in enumerate(last_row):
            last_row[i] = True

        for row in full_state_map[1: -1]:
            row[0] = row[-1] = True

        self.full_state_map = full_state_map

    def createWaterWalkMap(self):
        self.water_walk_map = set()

    def _clean_water_walk_map(self):
        self.water_walk_map.clear()

    def _get_four_direction_coordinates(self, i, j):
        return [
            (i - 1, j),
            (i, j + 1),
            (i + 1, j),
            (i, j - 1)
        ]

    def _set_full_state(self):
        for row, col in self.water_walk_map:
            if self.height_map[row][col] >= self.cur_high:
                self.full_state_map[row][col] = True

    def _fill_water(self):
        for row, col in self.water_walk_map:
            coord_high = self.height_map[row][col]
            if coord_high <= self.lower_wall:
                self.collected_walter += self.lower_wall - coord_high
                self.height_map[row][col] = self.lower_wall

    def _fill_lower_than_bord(self):
        for row in range(1, self.rows_cnt - 1):
            for col in range(1, self.cols_cnt - 1):
                cur_high = self.height_map[row][col]
                if cur_high < self.min_bord:
                    self.collected_walter += self.min_bord - cur_high
                    self.height_map[row][col] = self.min_bord

    def _is_on_bord(self, i, j):
        if i == 0 or i == self.rows_cnt - 1 or j == 0 or j == self.cols_cnt - 1:
            return True
        return False

    def _real_walk(self, i, j):
        if (i, j) in self.water_walk_map:
            return

        self.water_walk_map.add((i, j))
        coord_high = self.height_map[i][j]

        if coord_high > self.cur_high:
            self.lower_wall = coord_high if not self.lower_wall else min(self.lower_wall, coord_high)
            return

        on_bord = self._is_on_bord(i, j)
        if on_bord:
            self.can_fill_water = False
            return

        four_direction_coordinates = self._get_four_direction_coordinates(i, j)
        for coord in four_direction_coordinates:
            self._real_walk(*coord)

    def _exec_walk(self, i, j):
        self.water_walk_map.add((i, j))

        four_direction_coordinates = self._get_four_direction_coordinates(i, j)
        for coord in four_direction_coordinates:
            self._real_walk(*coord)

        if not self.can_fill_water:
            self._set_full_state()
            return

        self._fill_water()

    def _get_min_bord(self):
        min_bord = min(self.height_map[0] + self.height_map[-1])
        for row in self.height_map[1: -1]:
            min_bord = min(min_bord, row[0], row[-1])
        return min_bord

    def _get_max_high(self):
        max_high = -1
        for row in self.height_map:
            max_high = max(row + [max_high])
        return max_high

    def _water_walk(self):
        walter_full = True
        self.min_bord = self._get_min_bord()
        self.max_high = self._get_max_high()
        self._fill_lower_than_bord()
        if self.min_bord == self.max_high:
            return walter_full
        for i in range(1, self.rows_cnt):
            for j in range(1, self.cols_cnt):
                if self.full_state_map[i][j]:
                    continue
                self.cur_high = self.height_map[i][j]
                self.lower_wall = None
                self.can_fill_water = True
                self._clean_water_walk_map()
                self._exec_walk(i, j)

                if not self.can_fill_water:
                    continue

                walter_full = False

        return walter_full

    def trapRainWater(self, heightMap):
        """
        :type heightMap: List[List[int]]
        :rtype: int
        """
        self.collected_walter = 0
        self.rows_cnt = len(heightMap)
        self.cols_cnt = len(heightMap[0])
        self.height_map = heightMap

        if self.rows_cnt <= 2 or self.cols_cnt <= 2:
            return self.collected_walter

        self.createFullStateMap(heightMap)
        self.createWaterWalkMap()

        while True:
            walter_full = self._water_walk()
            if walter_full:
                return self.collected_walter

    def test_func(self):
        # func = self.trapRainWater
        func = foo
        if callable(func):
            print(self.__class__.__name__, func.__name__)


def foo():
    print('hello')


if __name__ == "__main__":
    solution = Solution()
    lst = [
      [1, 4, 3, 1, 3, 2],
      [3, 2, 1, 3, 2, 4],
      [2, 3, 3, 2, 3, 1]
    ]
    # print(solution.trapRainWater(lst))
    solution.test_func()

 

思路2,逆向思路

  • 最外圈格子一定接不到雨水,将最外圈格子的高度和坐标作为一个组合放到一个数据结构C中
  • 获取到C中高度最小的格子的坐标A,并从C中去掉A,因格子A在最外层,挨着他的比他矮的格子一定能接到水,且接到的水A的高度减去这个格子的高度,接完后将比较矮的格子的高度填充为A的高度
  • 挨着A的比A高的格子一定接不到水
  • 将挨着A的所有格子计算完毕,并将这些格子当前的高度及坐标填入到数据结构C中,且将这些格子标记为已核对
  • 再次重C中拿出当前高度最小的格子A,找其周围的格子进行对比,如果某个格子已经核对过,则不再核对该格子
  • 如果未核对过,则重复前面的比较过程并将格子的数据放到C中
  • 一直循环到C中没有数据则遍历完成
from heapq import heappush, heappop


class Solution(object):

    def createWall(self):
        for i in range(self.cols_cnt):
            last_row = self.rows_cnt - 1

            heappush(self.heap, (self.height_map[0][i], (0, i)))
            heappush(self.heap, (self.height_map[last_row][i], (last_row, i)))

            self.visited.add((0, i))
            self.visited.add((last_row, i))

        for i in range(self.rows_cnt):
            last_col = self.cols_cnt - 1

            heappush(self.heap, (self.height_map[i][0], (i, 0)))
            heappush(self.heap, (self.height_map[i][last_col], (i, last_col)))

            self.visited.add((i, 0))
            self.visited.add((i, last_col))

    def _get_four_direction_coordinates(self, i, j):
        return [
            (i - 1, j),
            (i, j + 1),
            (i + 1, j),
            (i, j - 1)
        ]

    def _is_out_bord_or_visited(self, i, j):
        if i <= 0 or i >= self.rows_cnt - 1 or j <= 0 or j >= self.cols_cnt - 1 or (i, j) in self.visited:
            return True
        return False

    def _calc(self):
        high, item = heappop(self.heap)
        self.current_lower_wall = max(self.current_lower_wall, high)
        for row, col in self._get_four_direction_coordinates(*item):
            if self._is_out_bord_or_visited(row, col):
                continue
            cur_high = self.height_map[row][col]
            if cur_high < self.current_lower_wall:
                self.collected_walter += self.current_lower_wall - cur_high
                self.height_map[row][col] = self.current_lower_wall
            self.visited.add((row, col))
            heappush(self.heap, (self.height_map[row][col], (row, col)))

    def _get_min_bord(self):
        min_bord = min(self.height_map[0] + self.height_map[-1])
        for row in self.height_map[1: -1]:
            min_bord = min(min_bord, row[0], row[-1])
        return min_bord

    def _get_max_high(self):
        max_high = -1
        for row in self.height_map:
            max_high = max(row + [max_high])
        return max_high

    def _fill_lower_than_bord(self):
        for row in range(1, self.rows_cnt - 1):
            for col in range(1, self.cols_cnt - 1):
                cur_high = self.height_map[row][col]
                if cur_high < self.min_bord:
                    self.collected_walter += self.min_bord - cur_high
                    self.height_map[row][col] = self.min_bord

    def _check_finish(self):
        self.min_bord = self._get_min_bord()
        self.max_high = self._get_max_high()
        self._fill_lower_than_bord()
        if self.min_bord == self.max_high:
            return True
        return False

    def trapRainWater(self, heightMap):
        """
        :type heightMap: List[List[int]]
        :rtype: int
        """
        self.collected_walter = 0
        self.rows_cnt = len(heightMap)
        self.cols_cnt = len(heightMap[0])
        self.height_map = heightMap
        self.heap = []
        self.visited = set()
        self.current_lower_wall = -1

        if self.rows_cnt <= 2 or self.cols_cnt <= 2:
            return self.collected_walter

        if self._check_finish():
            return self.collected_walter

        self.createWall()

        while self.heap:
            self._calc()
        return self.collected_walter


if __name__ == "__main__":
    solution = Solution()
    lst = [
      [1, 4, 3, 1, 3, 2],
      [3, 2, 1, 3, 2, 4],
      [2, 3, 3, 2, 3, 1]
    ]
    print(solution.trapRainWater(lst))

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值