diff --git a/121/memo.md b/121/memo.md new file mode 100644 index 0000000..05a71da --- /dev/null +++ b/121/memo.md @@ -0,0 +1,44 @@ +# 121. Best Time to Buy and Sell Stock + +- sol1.py: 配列を逆向きにたどり、将来の最大値を覚えておきながら、その日買ったときの利益を計算する +- sol2.py: 配列を順にたどり、過去の最小値を覚えておきながら、その日に売ったときの利益を計算する + +https://discord.com/channels/1084280443945353267/1206101582861697046/1219181674038820945 +> prices が空の場合は、何を返すことが想定されているでしょうか。 + +考えていなかったな + +> Haskell だと、scanl scanl1 の二つの関数があります。scanl1 は、リストの先頭を初期値として与えます。 +> つまり、scanl1 min prices というのが、そこまでの最小値のリストを返します。 + +https://discord.com/channels/1084280443945353267/1196472827457589338/1196473519689703444 +> 本質的には、 +> scanl min でその日までの最安の値。 +> zipWith (-) で利益。 +> max を取る。 + +https://github.com/mamo3gr/arai60/blob/121_best-time-to-buy-and-sell-stock/121_best-time-to-buy-and-sell-stock/memo.md +step1: 解法はほぼ同じだが、初期値をlistの先頭としている + コーナーケースを場合分け +step2: 上のHaskelのコードをpythonに直したもの。itertools.accumulateを使う +https://docs.python.org/ja/3/library/itertools.html#itertools.accumulate +- sol3.py + +https://github.com/naoto-iwase/leetcode/pull/42 +> どのスタイルに準拠するかによりますが、たとえば Google では import itertools -> itertools.islice といった使い方をします。 +> Use import statements for packages and modules only, not for individual types, classes, or functions. + +> Python 3.9 以降は built-in list を使うことになっています。 + +https://docs.python.org/3/library/typing.html#typing.List + +https://docs.python.org/3/library/typing.html#typing.List + +> Note that to annotate arguments, it is preferred to use an abstract collection type such as Sequence or Iterable rather than to use list or typing.List. + +> これは list 以外でもそうですが、引数の type hint はより abstract に、返り値はより specific にすることが多いかと思います。 + +色々知らなかった + +> 別の考え方として、「買う前の状態」「株を持っている状態」「売った状態」の3状態しかないので、それぞれの状態での最大の所持金(スタートを0とする)を考えるというのもあります。 + +なるほど、同じコードでも解釈を変えることができるのか diff --git a/121/sol1.py b/121/sol1.py new file mode 100644 index 0000000..0d56e5b --- /dev/null +++ b/121/sol1.py @@ -0,0 +1,9 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + max_price_in_current_or_future = -float("inf") + max_profits = [] + for price in prices[::-1]: + max_price_in_current_or_future = max(max_price_in_current_or_future, price) + max_profits.append(max_price_in_current_or_future - price) + + return max(max_profits) diff --git a/121/sol1_refactored.py b/121/sol1_refactored.py new file mode 100644 index 0000000..95f4a13 --- /dev/null +++ b/121/sol1_refactored.py @@ -0,0 +1,9 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + max_price = -float("inf") + max_profit = 0 + for price in prices[::-1]: + max_price = max(max_price, price) + max_profit = max(max_profit, max_price - price) + + return max_profit diff --git a/121/sol2.py b/121/sol2.py new file mode 100644 index 0000000..4bc6cab --- /dev/null +++ b/121/sol2.py @@ -0,0 +1,9 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + min_price_in_current_or_past = float("inf") + max_profits = [] + for price in prices: + min_price_in_current_or_past = min(min_price_in_current_or_past, price) + max_profits.append(price - min_price_in_current_or_past) + + return max(max_profits) diff --git a/121/sol2_refactored.py b/121/sol2_refactored.py new file mode 100644 index 0000000..bac208b --- /dev/null +++ b/121/sol2_refactored.py @@ -0,0 +1,9 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + min_price = float("inf") + max_profit = 0 + for price in prices: + min_price = min(min_price, price) + max_profit = max(max_profit, price - min_price) + + return max_profit diff --git a/121/sol3.py b/121/sol3.py new file mode 100644 index 0000000..43e9b54 --- /dev/null +++ b/121/sol3.py @@ -0,0 +1,13 @@ +import itertools + + +class Solution: + def maxProfit(self, prices: List[int]) -> int: + if not prices: + raise ValueError("The input list is empty") + + min_prices = itertools.accumulate(prices, min) + max_profit = [ + price - min_price for (price, min_price) in zip(prices, min_prices) + ] + return max(max_profit)