1. simple ()
  2. mixed valid ()[]{}
  3. deeply nested {[()]}
  4. mismatched (]
  5. close before open )(
  6. open never closed (((
  7. empty string -> true
  8. deep + parallel [({})]({})
コース一覧
コンピューターサイエンス入門:理論編
カッコのバランス判定 (スタック応用)

コンピューターサイエンス入門:理論編

2 進数、論理演算、ビット演算、データ構造、計算量、メモリモデルなど、プログラミングの土台となるコンピュータサイエンスの理論知識を学べるコースです。プログラミングを始めたばかりの学習者や、CS の体系的な土台を作りたい現役エンジニアを対象としています。約 13 時間 (1 日 30 分 × 26 日) で 53 レッスンを修了でき、修了後はコードのパフォーマンスや設計判断の根拠を理解した上で実装できるようになります。

1
2進数とビット演算
01. 2進数から10進数への変換5分
02. 10進数から2進数への変換5分
03. ビットAND演算でフラグ判定5分
04. OR / XOR でフラグを操作する5分
05. popcount で 1 のビット数を数える5分
06. シフト演算で 2 倍 / 半分5分
07. 16 進数から 10 進数への変換5分
08. 第 1 章まとめクイズ5分
2
文字コードと真偽値ロジック
01. 文字 → ASCII コード5分
02. コード → 文字5分
03. UTF-8 のバイト長を返す5分
04. AND / OR の真理値表5分
05. NOT / XOR の真理値表5分
06. 含意 (→) を AND/OR/NOT で表現5分
07. ド・モルガンの法則5分
08. 第2章まとめクイズ5分
3
計算量とBig-O
01. forループの実行回数を返す5分
02. 入れ子ループの実行回数5分
03. 線形探索 (O(n))5分
04. 二分探索 (O(log n))5分
05. バブルソート5分
06. 配列の最大と最小5分
07. 累積和で範囲合計5分
08. 第3章まとめクイズ5分
4
データ構造 (基本)
01. スタック (push/pop) を実装する5分
02. キュー (enqueue / dequeue) を実装する5分
03. カッコのバランス判定 (スタック応用)5分
04. set で重複を除去する5分
05. map で出現回数を数える5分
06. 二数の和 (map で O(n))5分
07. アナグラム判定5分
08. 第 4 章クイズ — データ構造 (基本)5分
5
ファイル / メモリ / IO 概念
01. バイト → KB 変換5分
02. ディスクサイズフォーマット5分
03. キャッシュヒット率5分
04. LRU 簡易シミュレーション5分
05. エンディアンの入れ替え (uint32)5分
06. バッファ範囲チェック5分
07. 第5章まとめクイズ5分
6
ネットワークと符号化
01. Base64 エンコード後の長さ計算5分
02. URL エンコード対象文字数5分
03. IPv4 アドレスを 32bit 整数に変換5分
04. 32bit 整数を IPv4 アドレスに変換5分
05. CIDR プレフィックスからネットマスクを作る5分
06. 単純チェックサム5分
07. 第6章まとめクイズ5分
7
設計と DB 基礎
01. 重複データを 1NF に変換 (フラットなリスト化)5分
02. キーで join (map 利用)5分
03. 残高転送のトランザクション風処理5分
04. CAP の availability 模擬5分
05. URL ルーティング5分
06. 疎結合と密結合 — 依存性注入で設計を変える12分
07. コース総まとめクイズ5分

カッコのバランス判定 (スタック応用)

<div><p></div></p> は、なぜ怒られるのか

HTML でこの形を書くと、エディタが赤い線を引きます。<div> を開き、<p> を開いた。ならば閉じるのは </p> が先で、</div> があとです。あとから開いたものほど、先に閉じなければならない からです。

これは HTML に限った話ではありません。( [ { の入れ子も、JSON も、プログラムのブロックも、全部同じ約束で動いています。だから 1 度この判定を書けるようになると、対応させるものが変わっても同じ手が使えます。

覚えておくのは、いちばん内側の 1 つだけ

一見すると、開いたものを全部覚えて突き合わせる必要がありそうです。実際にはそうではなく、閉じ側が来たときに確かめる相手は いま開いている中でいちばん内側の 1 つ だけです。

<div><ul><li></li></ul></div> を左から読んでいくと、開いたままのものは次のように増減します。

読んだところ開いたままのもの
<div>div
<ul>div, ul
<li>div, ul, li
</li>div, ul
</ul>div
</div>なし

閉じ側が来るたび、消えるのは常にいちばん右です。この動きは、前々回に見たスタックそのものです。

Python

opened = ["div", "ul", "li"] print(opened[-1]) # li いま閉じてよいのはこれだけ

だからスタックを 1 本用意して、開き側で積み、閉じ側で下ろす。それだけで判定できます。

閉じ側をキーにすると、引くのが 1 回で済む

対応表の向きには、良い向きと悪い向きがあります。判定する瞬間に手元にあるのは 閉じ側 なので、閉じ側から開き側を引ける形にしておくと、そのまま 1 回引くだけで相手が分かります。

Python

pairs = {"</div>": "<div>", "</p>": "<p>", "</li>": "<li>"} print(pairs["</p>"]) # <p>

逆向きに作ると、閉じ側から探すために表を全部なめることになります。どちらをキーにするかで、書く量も速さも変わります。

読み終わったときに、何も残っていないか

不正になる形は 3 つあります。

  1. 閉じ側が来たのに、開いているものが 1 つも無い
  2. 閉じ側が来たが、いちばん内側のものと種類が違う
  3. 最後まで読み終わったのに、開いたままのものが残っている

3 番目を忘れると、<div><div> のように開きっぱなしの文字列を正しいと答えてしまいます。読み終わった時点での確認を、必ず入れてください。

Python

opened = ["div", "div"] print(len(opened) == 0) # False 残っているので不正

どの手順も 1 タグぶんの処理しかしません。文字列を 1 回なめるだけなので、全体で O(n) です。

要件

  1. boolean を返す関数 isBalanced(s) を実装する
  2. スタックを使い O(n) で判定する
  3. 閉じカッコがスタックの top と一致しない、または途中でスタックが空になる、または終端でスタックが残るときは false

入出力例

isBalanced("()") → true isBalanced("()[]{}") → true isBalanced("{[()]}") → true isBalanced("(]") → false isBalanced(")(") → false isBalanced("(((") → false isBalanced("") → true isBalanced("[({})]({})") → true

ヒント

pairs = {')': '(', ']': '[', '}': '{'} のように 閉じ → 開き の対応表を持つと if が短くなる

閉じカッコのときは『スタックが空 or pop した top が相方と違う』を 1 行で判定できる

ループ後にスタックが空かどうかを必ずチェックする

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/19·更新 2026/08/26

関連レッスン

  • set で重複を除去する

    set を使って、整数配列から重複を取り除き、昇順ソート済みの配列を返す。

  • map で出現回数を数える

    ハッシュマップ (dict / Map) を使って、整数配列の各値の出現回数を 1 パスで集計する。

  • 二数の和 (map で O(n))

    配列の中から和が target となる 2 つの要素のインデックスを map を使って O(n) で見つける。

  • アナグラム判定

    2 つの文字列が同じ文字の並び替えになっているか (アナグラム) を、map による文字数カウントで判定する。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • HTMLHyperText Markup Languageの略。
  • applicationJSON 本文を送るときの Content-Type
  • ロック「他の人触らないでね」と DB に予約する
  • スタック後入れ先出し(LIFO)のデータ構造
  • 処理計算や代入を表す長方形
  • 関数処理に名前を付けて再利用できる単位
main.py
学習モード
エディタを読み込んでいます

メモ

カッコのバランス判定 (スタック応用)

⌘S で保存