Pythonで括弧の対応が取れているか(整形式か)を判定するプログラムの書き方
文字列処理の定番問題として、丸括弧「()」・波括弧「{}」・角括弧「[]」といった複数種類の括弧が混在する文字列が与えられ、その括弧がすべて正しく対応しているかどうか(バランスが取れている=整形式であるか)を判定する方法を解説します。
問題の概要
たとえば、入力が s = "([()()]{[]})()" のような文字列だった場合、開き括弧と閉じ括弧が正しい順序で対応しているため、出力は True になります。逆に、閉じ括弧が先に現れたり、種類の異なる括弧が交差していたりすると False を返す必要があります。
アルゴリズムの考え方:スタックを使う
この問題はスタック(Stack)というデータ構造を使うことで効率的に解けます。手順は以下の通りです。
- 空のリストをスタックとして用意します。
- 閉じ括弧に対応する開き括弧をハッシュマップ(辞書)で定義します。「}」→「{」、「)」→「(」、「]」→「[」というペアです。
- 文字列 s の各文字 c を先頭から順に走査します。
- c が閉じ括弧('}])' のいずれか)の場合:
- スタックが空、またはスタックの先頭要素が d[c](対応する開き括弧)と一致しなければ False を返します。
- 一致していれば、スタックから要素を取り出します(pop)。
- それ以外(開き括弧)の場合:
- その文字をスタックに積みます(push)。
- c が閉じ括弧('}])' のいずれか)の場合:
- 最後に、スタックが空なら True、残りがあれば False を返します。
この方法により、括弧の入れ子構造や対応関係を O(n) の計算量で一度の走査でチェックできます。
実装例
実際のPythonコードを見てみましょう。
class Solution:
def solve(self, s):
stack = []
d = {'}': '{', ')': '(', ']': '['}
for c in s:
if c in '}])':
if not stack or stack[-1] != d[c]:
return False
stack.pop()
else:
stack.append(c)
return not stack
ob = Solution()
print(ob.solve("([()()]{[]})()"))入力
"([()()]{[]})()"出力
True
コードのポイント
- 辞書 d:閉じ括弧をキー、対応する開き括弧を値とすることで、対応確認を1行で行えます。
- stack[-1]:Pythonでは負のインデックスで末尾要素にアクセスできるため、スタックの先頭参照が簡単です。
- return not stack:スタックが空のリストなら not により True になります。開き括弧が余っていれば False を返せます。
この手法は、コンパイラの構文解析やエディタのコード補完機能など、実際のソフトウェア開発でも広く応用されている基本的なテクニックです。ぜひ理解しておきましょう。
-
Pythonで2つの二分木の葉の並び(シーケンス)が同じかどうかを確認する方法
はじめに2つの二分木が与えられたとき、それぞれの木を左から右へたどったときの葉ノードの並び(シーケンス)が一致しているかどうかを判定する問題を考えてみましょう。例えば、次のような2つの木が入力として与えられた場合を想定します。この場合、どちらの木も葉の並びは [2, 6] となるため、出力は True になります。解決のアプローチこの問題を解くためには、以下の手順に従います。結果を格納するための新しいリスト c を用意します。inorder() 関数を定義します。この関数はルートノードとリスト c を引数に取ります。c が null の場合は、新しい空のリストを作成します。ルートノードが nu
-
Pythonで与えられたグラフが2部グラフかどうかを判定するプログラム
2部グラフとは無向グラフが与えられたとき、そのグラフが2部グラフ(バイパータイトグラフ)であるかどうかを判定する方法を解説します。2部グラフとは、グラフのすべての頂点を2つの集合 A と B に分割でき、グラフ内のすべての辺 {u, v} が必ず一方の端点 u が集合 A、もう一方の端点 v が集合 B に属するようなグラフのことです。つまり、同じ集合内の頂点同士を結ぶ辺(A-A や B-B)が一切存在しないグラフです。例として、次のようなグラフを考えてみましょう。この場合、頂点 [0, 4] を集合 A に、[1, 2, 3] を集合 B に分類できます。すべての辺は A から B、または