diff --git a/grind75_hard/03_42_Trapping Rain Water/level_1.py b/grind75_hard/03_42_Trapping Rain Water/level_1.py new file mode 100644 index 0000000..e791d79 --- /dev/null +++ b/grind75_hard/03_42_Trapping Rain Water/level_1.py @@ -0,0 +1,35 @@ +# brute force +# 現在地より左側の最大値が左の壁、右側の最大値が右の壁となる。 +# 現在地の水位は、左右の壁の小さいほうになる。 +# 現在地が壁より低ければ、水が貯まる。 +# O(n^2) +class Solution: + def trap(self, height: List[int]) -> int: + total_water = 0 + for i in range(1, len(height) - 1): # 両端には水が貯まらないので除外 + left_wall = max(height[:i]) + right_wall = max(height[i + 1 :]) + water_height = min(left_wall, right_wall) + if water_height < height[i]: + continue + total_water += water_height - height[i] + return total_water + + +# stackを使って実装 +# 左側の壁をstackで記憶し、右側の壁が見つかったら、貯まる水を計算する。 +class Solution: + def trap(self, height: List[int]) -> int: + left_walls = [] + total_water = 0 + for right in range(len(height)): + while left_walls and height[left_walls[-1]] <= height[right]: + bottom_index = left_walls.pop() + if not left_walls: + break + left = left_walls[-1] + distance = right - left - 1 + depth = min(height[left], height[right]) - height[bottom_index] + total_water += distance * depth + left_walls.append(right) + return total_water diff --git a/grind75_hard/03_42_Trapping Rain Water/level_2.py b/grind75_hard/03_42_Trapping Rain Water/level_2.py new file mode 100644 index 0000000..a17ac99 --- /dev/null +++ b/grind75_hard/03_42_Trapping Rain Water/level_2.py @@ -0,0 +1,16 @@ +# DPを使って解く +# brute forceと同じ考え方だが、左右の壁の最大値を記憶しておく +class Solution: + def trap(self, height: List[int]) -> int: + max_left = [0] * len(height) # [0,i]の範囲の最大値 + max_right = [0] * len(height) # [i,length)の範囲の最大値 + max_left[0] = height[0] + max_right[-1] = height[-1] + for i in range(1, len(height)): + max_left[i] = max(max_left[i - 1], height[i]) + max_right[-i - 1] = max(max_right[-i], height[-i - 1]) + total_water = 0 + for i in range(1, len(height) - 1): + water_height = min(max_left[i], max_right[i]) + total_water += water_height - height[i] + return total_water diff --git a/grind75_hard/03_42_Trapping Rain Water/level_3.py b/grind75_hard/03_42_Trapping Rain Water/level_3.py new file mode 100644 index 0000000..b43b02b --- /dev/null +++ b/grind75_hard/03_42_Trapping Rain Water/level_3.py @@ -0,0 +1,14 @@ +class Solution: + def trap(self, height: List[int]) -> int: + max_left = [0] * len(height) + max_right = [0] * len(height) + max_left[0] = height[0] + max_right[-1] = height[-1] + for i in range(1, len(height)): + max_left[i] = max(max_left[i - 1], height[i]) + max_right[-i - 1] = max(max_right[-i], height[-i - 1]) + total_water = 0 + for i in range(1, len(height) - 1): + water_height = min(max_left[i], max_right[i]) + total_water += water_height - height[i] + return total_water diff --git a/grind75_hard/03_42_Trapping Rain Water/level_4.py b/grind75_hard/03_42_Trapping Rain Water/level_4.py new file mode 100644 index 0000000..7a080d8 --- /dev/null +++ b/grind75_hard/03_42_Trapping Rain Water/level_4.py @@ -0,0 +1,37 @@ +# DPを使って解く +# 変数名を修正 +# max_height_in_rightはmax_heights_in_leftとは別のループで構築する +class Solution: + def trap(self, height: List[int]) -> int: + max_heights_in_left = [0] * len(height) # [0,i]の範囲の最大値 + max_height_in_right = [0] * len(height) # [i,length)の範囲の最大値 + max_heights_in_left[0] = height[0] + max_height_in_right[-1] = height[-1] + for i in range(1, len(height)): + max_heights_in_left[i] = max(max_heights_in_left[i - 1], height[i]) + for i in range(len(height) - 2, -1, -1): + max_height_in_right[i] = max(max_height_in_right[i + 1], height[i]) + total_water = 0 + for i in range(1, len(height) - 1): + water_height = min(max_heights_in_left[i], max_height_in_right[i]) + total_water += water_height - height[i] + return total_water + + +# stackを使って実装 +# 変数名を修正 +class Solution: + def trap(self, height: List[int]) -> int: + left_wall_indexes = [] + total_water = 0 + for right in range(len(height)): + while left_wall_indexes and height[left_wall_indexes[-1]] <= height[right]: + bottom_index = left_wall_indexes.pop() + if not left_wall_indexes: + break + left = left_wall_indexes[-1] + distance = right - left - 1 + depth = min(height[left], height[right]) - height[bottom_index] + total_water += distance * depth + left_wall_indexes.append(right) + return total_water diff --git a/grind75_hard/03_42_Trapping Rain Water/level_5.py b/grind75_hard/03_42_Trapping Rain Water/level_5.py new file mode 100644 index 0000000..dfa6e93 --- /dev/null +++ b/grind75_hard/03_42_Trapping Rain Water/level_5.py @@ -0,0 +1,39 @@ +# Space: O(1) +# 左右からポインタをずらしていく +# 片方のポインタは今までの最大値で止まるようにしておく +class Solution: + def trap(self, height: List[int]) -> int: + left_max = 0 + right_max = 0 + left = 0 + right = len(height) - 1 + total_water = 0 + while left < right: + if height[left] < height[right]: + left_max = max(left_max, height[left]) + total_water += left_max - height[left] + left += 1 + else: + right_max = max(right_max, height[right]) + total_water += right_max - height[right] + right -= 1 + return total_water + + +# DPを使って解く +# 変数名を修正 +class Solution: + def trap(self, height: List[int]) -> int: + max_heights_in_left = [0] * len(height) # [0,i]の範囲の最大値 + max_heights_in_right = [0] * len(height) # [i,length)の範囲の最大値 + max_heights_in_left[0] = height[0] + max_heights_in_right[-1] = height[-1] + for i in range(1, len(height)): + max_heights_in_left[i] = max(max_heights_in_left[i - 1], height[i]) + for i in range(len(height) - 2, -1, -1): + max_heights_in_right[i] = max(max_heights_in_right[i + 1], height[i]) + total_water = 0 + for i in range(1, len(height) - 1): + water_height = min(max_heights_in_left[i], max_heights_in_right[i]) + total_water += water_height - height[i] + return total_water