Pythonで株価が利益になるまでの最短待機日数を求めるプログラム
問題概要
ある企業の日々の株価が、時系列順に並んだリストとして与えられているとします。ここで、元のリストと同じ長さの新しいリストを作成することを考えます。新しいリストのインデックス i の値は、「その日の株価を上回る価格が現れるまでに何日待てばよいか」という最小日数を表します。もし将来どの日を見ても利益を得られる見込みがない場合は、その値は 0 とします。
例えば、入力が prices = [4, 3, 5, 9, 7, 6] の場合、出力は [2, 1, 1, 0, 0, 0] となります。
- インデックス 0(価格 4):2 日後に価格 5 となり利益を得られます
- インデックス 1(価格 3):1 日後に価格 5 となり利益を得られます
- インデックス 2(価格 5):1 日後に価格 9 となり利益を得られます
- インデックス 3 以降:それ以降にこれらの価格を上回る日は存在しないため 0 です
解法のアプローチ:単調スタック
この問題は「単調スタック(Monotonic Stack)」というテクニックを使うことで効率的に解くことができます。各日について未来を総当たりで調べると O(n²) かかりますが、スタックを活用すれば O(n) で処理できます。
具体的な手順は以下の通りです。
- ans := prices と同じサイズのリストを用意し、すべて 0 で初期化する
- q := 空のリスト(スタック)を用意する。スタックには (インデックス, 価格) のペアを格納する
- prices の各インデックス i と価格 p について、以下を繰り返す:
- q が空でなく、かつ p が q の末尾要素の価格より大きい間、次を繰り返す:
- j := q の末尾要素のインデックス
- ans[j] := i - j(j 日目から i 日目までの待ち日数を記録)
- q から末尾要素を削除する
- (i, p) を q の末尾に追加する
- q が空でなく、かつ p が q の末尾要素の価格より大きい間、次を繰り返す:
- 最後に ans を返す
このアルゴリズムでは、現在の価格がスタック内の過去の価格を上回るたびに、それらの「待ち日数」が確定していきます。各要素は最大 1 回しかプッシュ・ポップされないため、全体の計算量は O(n) に抑えられます。
Pythonでの実装例
class Solution:
def solve(self, prices):
ans = [0 for _ in prices]
q = []
for i, p in enumerate(prices):
while q and p > q[-1][1]:
j = q[-1][0]
ans[j] = i - j
q.pop()
q.append((i, p))
return ans
ob = Solution()
prices = [4, 3, 5, 9, 7, 6]
print(ob.solve(prices))
入力
[4, 3, 5, 9, 7, 6]
出力
[2, 1, 1, 0, 0, 0]
まとめ
本記事では、単調スタックを用いて「利益が出るまでの最短待機日数」を効率的に求める方法を紹介しました。全探索では O(n²) となる問題を、O(n) の時間計算量で解ける点がこの手法の大きな魅力です。株価の分析だけでなく、「次により大きい要素(Nearest Greater Element)」系の問題全般に応用できる汎用的なテクニックなので、ぜひ覚えておきましょう。
-
Pythonで色のマージ後に残る最小個数を求めるプログラム
問題概要 赤(R)、緑(G)、青(B)の3種類の色からなるリストを考えます。隣り合う異なる2つの色は、残りの「第3の色」1個に変換(マージ)できます。この変換を好きな順序で何度でも繰り返してよいとき、最終的に残る要素数の最小値を求めるのがこの問題です。 たとえば入力が colors = [G, R, G, B, R] の場合、次のように変換を進めることで最終的に1個まで減らせます。したがって出力は 1 となります。 解き方のアプローチ 一見すると状態探索が必要そうな問題ですが、実はXOR(排他的論理和)を使ったシンプルな判定だけで答えが求まります。手順は以下の通りです。 n := 色リス
-
Pythonで文字列tを別の文字列sの部分文字列にするために必要な最小操作回数を求めるプログラム
問題の概要2つの文字列 s と t が与えられたとき、t を s の部分文字列にするために必要な最小の操作回数を求めます。ここでいう1回の操作とは、「s 内の任意の位置を選び、その位置の文字を任意の別の文字に変更する」ことを指します。例えば、入力が s = abbpqr、t = bbxy の場合、出力は 2 になります。これは、s の部分文字列 bbpq に着目し、p を x に、q を y に変更することで t = bbxy と一致させられるためです。解法のアプローチこの問題はスライディングウィンドウ(全開始位置の走査)を使うことで簡単に解けます。s の中で長さ k(= t の長さ)に等しい