Pythonで「毎日の気温」問題を解く:単調スタックを使った効率的なアルゴリズム
問題の概要
毎日の気温を表すリスト T が与えられたとします。このとき、入力の各日について「より暖かい気温になるまで何日待つ必要があるか」を示すリストを返すことが求められます。将来により暖かい日が存在しない場合は、代わりに 0 を格納します。
例えば、T = [73, 74, 75, 71, 69, 72, 76, 73] の場合、出力は [1, 1, 4, 2, 1, 1, 0, 0] となります。
この問題は、単調スタック(Monotonic Stack)と呼ばれるテクニックを使うことで、効率的に解くことができます。
解法のアプローチ
具体的な手順は以下の通りです。
- ans := T と同じサイズの配列を作成し、すべて 0 で初期化する
- スタックを1つ定義し、0 を挿入する。また i := 1 とする
- i が T の長さ未満である間、以下を繰り返す
- スタックが空でなく、かつ T[i] > T[スタックの先頭要素] である間、以下を繰り返す
- index := スタックの先頭要素
- ans[index] := i − index
- スタックから先頭要素を削除する
- スタックの長さが 0、または T[i] <= T[スタックの先頭要素] の場合
- i をスタックに挿入する
- i を 1 増やす
- スタックが空でなく、かつ T[i] > T[スタックの先頭要素] である間、以下を繰り返す
- ans を返す
Pythonでの実装例
以下の実装を見ると、処理の流れがより理解しやすくなります。
class Solution(object):
def dailyTemperatures(self, T):
ans = [0 for i in range(len(T))]
stack = []
stack.append(0)
i = 1
while i < len(T):
while len(stack) and T[i] > T[stack[-1]]:
index = stack[-1]
ans[index] = i - index
stack.pop()
if not len(stack) or T[i] <= T[stack[-1]]:
stack.append(i)
i += 1
return ans
ob1 = Solution()
print(ob1.dailyTemperatures([73, 74, 75, 71, 69, 72, 76, 73]))
入力
[73, 74, 75, 71, 69, 72, 76, 73]
出力
[1, 1, 4, 2, 1, 1, 0, 0]
計算量について
このアルゴリズムの時間計算量は O(n) です。各インデックスは最大でもスタックに1回プッシュされ、1回ポップされるだけだからです。素朴な二重ループによる O(n²) の解法と比べて大幅に高速化できます。空間計算量も O(n) となり、スタックと結果配列の分の領域が必要になります。
-
Pythonで二分木の中間順トラバーサル(Inorder Traversal)を再帰なしで実装する方法
二分木(バイナリツリー)が与えられたとき、再帰を使わずに中間順トラバーサル(Inorder Traversal)で木を走査する方法を解説します。例えば、次のような二分木があるとします。この木に対して中間順トラバーサルを行うと、結果は [2,5,7,10,15,20] のようになります。中間順トラバーサルは「左の子 → 親ノード → 右の子」の順にノードを訪問するため、二分探索木の場合は値が昇順に出力されるという特徴があります。アルゴリズムの考え方再帰を使わずにスタックを活用することで、この問題を解決できます。手順は以下のとおりです。結果を格納する配列 res と、ノードを一時的に保持するスタッ
-
Pythonのリストをスタックとキューとして使う方法を徹底解説
本記事では、Python 3.x(およびそれ以前のバージョン)におけるスタック(Stack)とキュー(Queue)という基本的なデータ構造について解説します。それぞれのデータ構造の仕組みや操作方法を、実際のコード例とともにわかりやすく学んでいきましょう。 本記事で扱う主なトピックは以下の通りです。 挿入操作(Push / Enqueue) 削除操作(Pop / Dequeue) 表示・走査(トラバース)操作 前提知識:リストとリスト操作の基礎関連するデータ構造:リスト操作 スタック(Stack)とは スタックでは、オブジェクトが積み重なるように格納され、取り出す際には到着した順序とは逆の順