From a55234f1a20a46eb1a99084fd075fcfc2b03cf18 Mon Sep 17 00:00:00 2001 From: tom4649 Date: Mon, 8 Jun 2026 07:14:43 +0900 Subject: [PATCH 1/3] step1, 2 --- 0152.Maximum-Product-Subarray/memo.md | 27 ++++++++ 0152.Maximum-Product-Subarray/step1.py | 65 +++++++++++++++++++ .../step1_revised.py | 52 +++++++++++++++ 0152.Maximum-Product-Subarray/step2_dp.py | 16 +++++ 0152.Maximum-Product-Subarray/step2_dp2.py | 25 +++++++ .../step2_two_way.py | 20 ++++++ 6 files changed, 205 insertions(+) create mode 100644 0152.Maximum-Product-Subarray/memo.md create mode 100644 0152.Maximum-Product-Subarray/step1.py create mode 100644 0152.Maximum-Product-Subarray/step1_revised.py create mode 100644 0152.Maximum-Product-Subarray/step2_dp.py create mode 100644 0152.Maximum-Product-Subarray/step2_dp2.py create mode 100644 0152.Maximum-Product-Subarray/step2_two_way.py diff --git a/0152.Maximum-Product-Subarray/memo.md b/0152.Maximum-Product-Subarray/memo.md new file mode 100644 index 0000000..6405291 --- /dev/null +++ b/0152.Maximum-Product-Subarray/memo.md @@ -0,0 +1,27 @@ +# 152. Maximum Product Subarray + +## step1 + +24mほど書いたが、デバッグして答えを合わせた。かなりコードが冗長になった。 + +計算量 時間:O(n):空間:O(n) + +改善する: step1_revised。iteratorを使って空間をO(1)にした。 + +## step2 + +DPで解くこともできる: step2_dp.py + +他の人のコード + +https://discord.com/channels/1084280443945353267/1196498607977799853/1358736384604766238 + +DPの書き方が若干違った。0を特別扱いするか否か。Kadaneのアルゴリズムに似ている? + +もう一つは自分と似ているようだが2回計算している。 + +Pythonに変換しながらロジックを追った。議論を理解しきれていないのでもう少し読む。 + + +## step3 +TODO。もう少し考える。 diff --git a/0152.Maximum-Product-Subarray/step1.py b/0152.Maximum-Product-Subarray/step1.py new file mode 100644 index 0000000..38fc2fa --- /dev/null +++ b/0152.Maximum-Product-Subarray/step1.py @@ -0,0 +1,65 @@ +import math + + +class Solution: + def maxProduct(self, nums: list[int]) -> int: + if not nums: + raise ValueError("input is empty") + + def max_product_helper(first, last): + if first == last: + return nums[first] + + num_negative = 0 + for n in nums[first : last + 1]: + if n < 0: + num_negative += 1 + if num_negative % 2 == 0: + return math.prod(nums[first : last + 1]) + + first_negative = first + product_up_to_first_negative = nums[first_negative] + while first_negative <= last and nums[first_negative] > 0: + first_negative += 1 + if first_negative <= last: + product_up_to_first_negative *= nums[first_negative] + + if first_negative > last: + return product_up_to_first_negative + if first_negative == last: + return math.prod(nums[first:first_negative]) + + last_negative = last + product_until_last_negative = nums[last_negative] + while last_negative >= first and nums[last_negative] > 0: + last_negative -= 1 + if last_negative >= first: + product_until_last_negative *= nums[last_negative] + + if abs(product_up_to_first_negative) < abs(product_until_last_negative): + print( + first_negative, last, math.prod(nums[first_negative + 1 : last + 1]) + ) + return math.prod(nums[first_negative + 1 : last + 1]) + else: + print(first, last_negative, math.prod(nums[first:last_negative])) + return math.prod(nums[first:last_negative]) + + max_product = nums[-1] + + begin = 0 + while begin < len(nums): + while begin < len(nums) and nums[begin] == 0: + begin += 1 + if begin == len(nums): + continue + end = begin + 1 + while end < len(nums) and nums[end] != 0: + end += 1 + print(begin, end, max_product_helper(begin, end - 1)) + max_product = max(max_product, max_product_helper(begin, end - 1)) + begin = end + 1 + if begin < len(nums): + max_product = max(max_product, 0) + + return max_product diff --git a/0152.Maximum-Product-Subarray/step1_revised.py b/0152.Maximum-Product-Subarray/step1_revised.py new file mode 100644 index 0000000..41191a0 --- /dev/null +++ b/0152.Maximum-Product-Subarray/step1_revised.py @@ -0,0 +1,52 @@ +import math + + +class Solution: + def maxProduct(self, nums: list[int]) -> int: + if not nums: + raise ValueError("input is empty") + + max_product = nums[0] + if 0 in nums: + max_product = max(max_product, 0) + + def max_product_no_zero_between(begin: int, end: int) -> int | float: + if begin >= end: + return float("-inf") + if end - begin == 1: + return nums[begin] + + num_negative = sum(1 for i in range(begin, end) if nums[i] < 0) + + if num_negative % 2 == 0: + return math.prod(nums[i] for i in range(begin, end)) + + first_negative_index = next(i for i in range(begin, end) if nums[i] < 0) + last_negative_index = next( + i for i in range(end - 1, begin - 1, -1) if nums[i] < 0 + ) + + prod_after_first = math.prod( + nums[i] for i in range(first_negative_index + 1, end) + ) + prod_before_last = math.prod( + nums[i] for i in range(begin, last_negative_index) + ) + + return max(prod_after_first, prod_before_last) + + begin = 0 + for i in range(len(nums)): + if nums[i] == 0: + if begin < i: + max_product = max( + max_product, max_product_no_zero_between(begin, i) + ) + begin = i + 1 + + if begin < len(nums): + max_product = max( + max_product, max_product_no_zero_between(begin, len(nums)) + ) + + return max_product diff --git a/0152.Maximum-Product-Subarray/step2_dp.py b/0152.Maximum-Product-Subarray/step2_dp.py new file mode 100644 index 0000000..f585942 --- /dev/null +++ b/0152.Maximum-Product-Subarray/step2_dp.py @@ -0,0 +1,16 @@ +class Solution: + def maxProduct(self, nums: list[int]) -> int: + global_max = nums[0] + max_product = nums[0] + min_prduct = nums[0] + + for n in nums[1:]: + if n < 0: + max_product, min_prduct = min_prduct, max_product + + max_product = max(n, max_product * n) + min_prduct = min(n, min_prduct * n) + + global_max = max(global_max, max_product) + + return global_max diff --git a/0152.Maximum-Product-Subarray/step2_dp2.py b/0152.Maximum-Product-Subarray/step2_dp2.py new file mode 100644 index 0000000..843b42b --- /dev/null +++ b/0152.Maximum-Product-Subarray/step2_dp2.py @@ -0,0 +1,25 @@ +class Solution: + def maxProduct(self, nums: list[int]) -> int: + if len(nums) == 1: + return nums[0] + + result = 0 + plus_max = 0 + minus_max = 0 + + for num in nums: + if num == 0: + plus_max = 0 + minus_max = 0 + else: + if plus_max == 0: + plus_max = 1 + if num < 0: + plus_max, minus_max = minus_max, plus_max + + plus_max *= num + minus_max *= num + + result = max(result, plus_max) + + return result diff --git a/0152.Maximum-Product-Subarray/step2_two_way.py b/0152.Maximum-Product-Subarray/step2_two_way.py new file mode 100644 index 0000000..4ad2363 --- /dev/null +++ b/0152.Maximum-Product-Subarray/step2_two_way.py @@ -0,0 +1,20 @@ +class Solution: + def maxProduct(self, nums: list[int]) -> int: + def update_max_product(self, nums: list[int], max_product: int) -> int: + product = 1 + for num in nums: + if product == 0: + product = 1 + + product *= num + max_product = max(max_product, product) + + return max_product + + max_product = float("-inf") + max_product = self.update_max_product(nums, max_product) + + nums.reverse() + max_product = self.update_max_product(nums, max_product) + + return max_product From 45c6e63ca62fd13019247c40f292ff14676ea6bd Mon Sep 17 00:00:00 2001 From: tom4649 Date: Tue, 9 Jun 2026 07:26:06 +0900 Subject: [PATCH 2/3] Add step3 --- 0152.Maximum-Product-Subarray/memo.md | 17 ++++--- .../step1_revised.py | 2 +- 0152.Maximum-Product-Subarray/step2_dp.py | 14 +++--- 0152.Maximum-Product-Subarray/step2_dp2.py | 5 ++ .../step2_dp2_float.py | 31 ++++++++++++ .../step2_two_way.py | 16 ++++-- 0152.Maximum-Product-Subarray/step3.py | 50 +++++++++++++++++++ 7 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 0152.Maximum-Product-Subarray/step2_dp2_float.py create mode 100644 0152.Maximum-Product-Subarray/step3.py diff --git a/0152.Maximum-Product-Subarray/memo.md b/0152.Maximum-Product-Subarray/memo.md index 6405291..69c3aff 100644 --- a/0152.Maximum-Product-Subarray/memo.md +++ b/0152.Maximum-Product-Subarray/memo.md @@ -10,18 +10,23 @@ ## step2 -DPで解くこともできる: step2_dp.py -他の人のコード +Solutionsを見るとDPで解くこともできるようだ。Kadaneのアルゴリズムに似ている?: step2_dp.py + +## 他の人のコード https://discord.com/channels/1084280443945353267/1196498607977799853/1358736384604766238 -DPの書き方が若干違った。0を特別扱いするか否か。Kadaneのアルゴリズムに似ている? +DPの書き方が若干違った。0を特別扱いするか否か。 + +float版に拡張もできる(初期化を変える必要はないように思うが)。テストの途中を追うことでやっと理解できた。minus_maxは-1をかけたときに最大値になるものを保持している。 + +step2_two_way.pyは、「0を含まない区間に負の数が奇数個の場合には、最右または最左の負の数までの最大値が答えとなる」ことを利用し、左と右で2回計算して答えを求めている。 -もう一つは自分と似ているようだが2回計算している。 +Pythonに変換しながらロジックを追った。 -Pythonに変換しながらロジックを追った。議論を理解しきれていないのでもう少し読む。 +自分の解法よりロジックがわかりやすくコードもシンプル。 ## step3 -TODO。もう少し考える。 +書く diff --git a/0152.Maximum-Product-Subarray/step1_revised.py b/0152.Maximum-Product-Subarray/step1_revised.py index 41191a0..1c36d9b 100644 --- a/0152.Maximum-Product-Subarray/step1_revised.py +++ b/0152.Maximum-Product-Subarray/step1_revised.py @@ -12,7 +12,7 @@ def maxProduct(self, nums: list[int]) -> int: def max_product_no_zero_between(begin: int, end: int) -> int | float: if begin >= end: - return float("-inf") + return -math.inf if end - begin == 1: return nums[begin] diff --git a/0152.Maximum-Product-Subarray/step2_dp.py b/0152.Maximum-Product-Subarray/step2_dp.py index f585942..5b801e6 100644 --- a/0152.Maximum-Product-Subarray/step2_dp.py +++ b/0152.Maximum-Product-Subarray/step2_dp.py @@ -1,16 +1,16 @@ class Solution: def maxProduct(self, nums: list[int]) -> int: - global_max = nums[0] max_product = nums[0] - min_prduct = nums[0] + sub_max_product = nums[0] + sub_min_prduct = nums[0] for n in nums[1:]: if n < 0: - max_product, min_prduct = min_prduct, max_product + sub_max_product, sub_min_prduct = sub_min_prduct, sub_max_product - max_product = max(n, max_product * n) - min_prduct = min(n, min_prduct * n) + sub_max_product = max(n, sub_max_product * n) + sub_min_prduct = min(n, sub_min_prduct * n) - global_max = max(global_max, max_product) + max_product = max(max_product, sub_max_product) - return global_max + return max_product diff --git a/0152.Maximum-Product-Subarray/step2_dp2.py b/0152.Maximum-Product-Subarray/step2_dp2.py index 843b42b..9c400e9 100644 --- a/0152.Maximum-Product-Subarray/step2_dp2.py +++ b/0152.Maximum-Product-Subarray/step2_dp2.py @@ -23,3 +23,8 @@ def maxProduct(self, nums: list[int]) -> int: result = max(result, plus_max) return result + + +sol = Solution() +nums = [0.1, 0.2, 0.1] +print(sol.maxProduct(nums)) diff --git a/0152.Maximum-Product-Subarray/step2_dp2_float.py b/0152.Maximum-Product-Subarray/step2_dp2_float.py new file mode 100644 index 0000000..907666f --- /dev/null +++ b/0152.Maximum-Product-Subarray/step2_dp2_float.py @@ -0,0 +1,31 @@ +class Solution: + def maxProduct(self, nums: list[float]) -> float: + if len(nums) == 1: + return nums[0] + + result = 0 + plus_max = 0 + minus_max = 0 + + for num in nums: + if num == 0: + plus_max = 0 + minus_max = 0 + continue + if plus_max < 1: + plus_max = 1 + if num < 0: + plus_max, minus_max = minus_max, plus_max + + plus_max *= num + minus_max *= num + # print(plus_max, minus_max) + + result = max(result, plus_max) + + return result + + +sol = Solution() +nums = [0.1, -0.2, -2] +print(sol.maxProduct(nums)) diff --git a/0152.Maximum-Product-Subarray/step2_two_way.py b/0152.Maximum-Product-Subarray/step2_two_way.py index 4ad2363..c44142d 100644 --- a/0152.Maximum-Product-Subarray/step2_two_way.py +++ b/0152.Maximum-Product-Subarray/step2_two_way.py @@ -1,6 +1,9 @@ +import math + + class Solution: def maxProduct(self, nums: list[int]) -> int: - def update_max_product(self, nums: list[int], max_product: int) -> int: + def update_max_product(nums: list[int], max_product: int) -> int: product = 1 for num in nums: if product == 0: @@ -11,10 +14,15 @@ def update_max_product(self, nums: list[int], max_product: int) -> int: return max_product - max_product = float("-inf") - max_product = self.update_max_product(nums, max_product) + max_product = -math.inf + max_product = update_max_product(nums, max_product) nums.reverse() - max_product = self.update_max_product(nums, max_product) + max_product = update_max_product(nums, max_product) return max_product + + +sol = Solution() +nums = [0.1, 0.2, 0.1] +print(sol.maxProduct(nums)) diff --git a/0152.Maximum-Product-Subarray/step3.py b/0152.Maximum-Product-Subarray/step3.py new file mode 100644 index 0000000..73604c7 --- /dev/null +++ b/0152.Maximum-Product-Subarray/step3.py @@ -0,0 +1,50 @@ +import math + + +class Solution: + def maxProduct(self, nums: list[int]) -> int: + def update_max_product(nums, max_product): + product = 1 + for num in nums: + if product == 0: + product = 1 + + product *= num + max_product = max(max_product, product) + + return max_product + + max_product = -math.inf + max_product = update_max_product(nums, max_product) + + nums.reverse() + max_product = update_max_product(nums, max_product) + + return max_product + + +class Solution: + def maxProduct(self, nums: list[int]) -> int: + if len(nums) == 1: + return nums[0] + + max_product = 0 + plus_max = 0 + minus_max = 0 + + for num in nums: + if num == 0: + plus_max = 0 + minus_max = 0 + else: + if plus_max == 0: + plus_max = 1 + if num < 0: + plus_max, minus_max = minus_max, plus_max + + plus_max *= num + minus_max *= num + + max_product = max(max_product, plus_max) + + return max_product From e2b6d581eef20d1fbcd1466847e623531e391e94 Mon Sep 17 00:00:00 2001 From: tom4649 Date: Wed, 10 Jun 2026 19:26:26 +0900 Subject: [PATCH 3/3] Fix typo --- 0152.Maximum-Product-Subarray/step2_dp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/0152.Maximum-Product-Subarray/step2_dp.py b/0152.Maximum-Product-Subarray/step2_dp.py index 5b801e6..2424c69 100644 --- a/0152.Maximum-Product-Subarray/step2_dp.py +++ b/0152.Maximum-Product-Subarray/step2_dp.py @@ -2,14 +2,14 @@ class Solution: def maxProduct(self, nums: list[int]) -> int: max_product = nums[0] sub_max_product = nums[0] - sub_min_prduct = nums[0] + sub_min_product = nums[0] for n in nums[1:]: if n < 0: - sub_max_product, sub_min_prduct = sub_min_prduct, sub_max_product + sub_max_product, sub_min_product = sub_min_product, sub_max_product sub_max_product = max(n, sub_max_product * n) - sub_min_prduct = min(n, sub_min_prduct * n) + sub_min_product = min(n, sub_min_product * n) max_product = max(max_product, sub_max_product)