1. [2, 7, 9, 3, 1] -> 12
  2. [1, 2, 3, 1] -> 4
  3. 1 要素 [5] -> 5
  4. 2 要素 [2, 1] -> 2
  5. 2 要素 [1, 2] -> 2
  6. [2, 1, 1, 2] -> 4
コース一覧
コンピューターサイエンス上級:アルゴリズムとデータ構造
隣り合わない最大値 (House Robber)

コンピューターサイエンス上級:アルゴリズムとデータ構造

探索、ソート、木、グラフ、動的計画法、貪欲法など、競技プログラミングや技術面接で問われる高度なアルゴリズムとデータ構造を学べるコースです。基本的な CS の知識を持ち、アルゴリズム力を伸ばしたい学習者や、外資・大手の技術面接対策をしたい方を対象としています。約 13 時間 (1 日 30 分 × 26 日) で 50 レッスンを修了でき、修了後はコーディング面接の実装問題を構造的に解けるようになります。

1
連結リスト
01. リンクリスト構築と長さの計算5分
02. リンクリストの反転5分
03. リンクリストのサイクル検出5分
04. ソート済みリンクリストの merge5分
05. リンクリストの中央ノード取得5分
06. ソート済みリストの重複削除5分
07. 第1章まとめクイズ5分
2
二分木
01. 二分木の in-order 走査5分
02. 二分木の pre-order 走査5分
03. 二分木の post-order 走査5分
04. 二分木の幅優先走査 (BFS)5分
05. 二分木の高さ5分
06. 二分木の平衡判定5分
07. 第2章まとめクイズ — 二分木5分
3
探索木 (BST)
01. BST に値を挿入する5分
02. BST から値を検索する5分
03. BST の最小値と最大値5分
04. BST 妥当性チェック5分
05. BST で k 番目に小さい値5分
06. BST から値を削除する5分
07. 第 3 章 まとめクイズ5分
4
ハッシュとセット
01. hashmap で頻度集計5分
02. キーでグループ化5分
03. two sum (hash で O(n))5分
04. 部分配列の和 = k の個数5分
05. 最長連続部分列5分
06. 集合の積 (intersection)5分
07. 第4章まとめクイズ5分
5
グラフ
01. グラフ BFS で連結成分サイズを求める5分
02. グラフ DFS で連結成分の数を数える5分
03. グラフのパス存在判定5分
04. BFS で最短経路の長さを求める5分
05. トポロジカルソート5分
06. 2 部グラフ判定5分
07. ダイクストラ法 — 重み付きグラフの最短経路15分
08. 第5章まとめクイズ — グラフ5分
6
動的計画法 (上級)
01. 編集距離 (レーベンシュタイン距離)5分
02. 最長増加部分列(LIS)の解法 ── AOJ 2430 対応の動的計画法5分
03. 最大部分配列和 (Kadane)5分
04. 隣り合わない最大値 (House Robber)5分
05. グリッド経路数 (Unique Paths)5分
06. 単語分割可能か (Word Break)5分
07. 第6章まとめクイズ — 動的計画法 (上級)5分
7
総合データ構造と関数型
01. map と filter を組み合わせる5分
02. reduce で積を計算5分
03. 関数合成5分
04. カリー化5分
05. trie の単純検索 (prefix マッチ)5分
06. Union-Find (連結成分数)5分
07. 最終総まとめクイズ5分

隣り合わない最大値 (House Robber)

大きい順に取ると、負ける

数字が一列に並んでいて、そこから好きなだけ選んで合計を最大にします。ただし 隣り合う 2 つは同時に選べません。[2, 7, 9, 3, 1] なら、2 と 9 と 1 で 12 が最大です。一番大きい 9 を含む選び方が正解ですが、2 番目に大きい 7 は 9 の隣なので使えません。

まず思いつくのは、大きいものから順に取って隣だけ避ける方法です。[2, 1, 1, 2] で試してみます。

先頭の 2 を取ります。隣の 1 は取れません。次の 1 を取ります。すると最後の 2 が隣になって取れず、合計は 3 です。正解は両端の 2 と 2 で 4 なので、負けています。

目の前で一番得に見える選択が、後の選択肢を潰す。だからその場で決め切らず、両方の場合を最後まで持って比べる必要があります。

1 つずつ「取る」と「飛ばす」を比べる

左から 1 つずつ見ていき、「ここまでで作れる最大」を更新していきます。今見ている要素について、道は 2 本しかありません。

  • 飛ばす — 答えは 1 つ前までの最大と同じ
  • 取る — 1 つ前は使えないので、2 つ前までの最大に今の値を足す

大きいほうを選んで、今の答えにします。これを最後まで繰り返すだけです。ここで比べているのは要素の大きさではなく、そこまでの合計 である点に注意してください。

[2, 1, 1, 2] で追うと、答えは 2、2、3、4 と進みます。3 番目では、2 つ前までの 2 に今の 1 を足した 3 が、1 つ前までの 2 を上回りました。最後は、2 つ前までの 2 に 2 を足した 4 が、1 つ前までの 3 を上回ります。貪欲では逃した 4 が、ちゃんと出ています。

貪欲との違いは、3 番目で 1 を取ったことを確定させていない点です。取った場合と取らなかった場合の両方の合計を持ったまま先へ進むので、最後にひっくり返せます。

覚えるのは直前 2 つだけ

式に出てくるのは「1 つ前」と「2 つ前」だけで、それより古い値は二度と使いません。だから配列を全部持たなくても、変数 2 つで足ります。

このとき更新の順番に注意が要ります。

Python

# 正しい。右辺を全部読んでから、まとめて代入する prev2, prev1 = prev1, current # 間違い。prev1 を先に書き換えると、次の行の prev1 が新しい値になっている prev1 = current prev2 = prev1

変数 2 つを両方 0 から始めると、要素が 0 個のときも 1 個のときも場合分けなしで正しく動きます。配列を作る書き方にすると、先頭と 2 番目の初期値を別に決める必要が出てきます。

やってみよう

  • [1, 2, 3, 1] の答えは 4。2 と 1 を選んだ 3 ではない
  • [2, 1] と [1, 2] はどちらも 2。隣り合っているので片方しか選べない
  • 一列ではなく輪になっていたら (先頭と末尾も隣) どうなるか考える。先頭を除いた場合と末尾を除いた場合で 2 回計算するのが定石

要件

  1. 戻り値は選んだ要素の最大合計 (整数)
  2. 隣り合う 2 要素を同時に選んではいけない
  3. 空配列は 0、1 要素はその値を返す

入出力例

rob([2,7,9,3,1]) → 12 rob([1,2,3,1]) → 4 rob([5]) → 5 rob([2,1]) → 2 rob([1,2]) → 2 rob([2,1,1,2]) → 4

ヒント

dp[i] = i 番目までの最大合計、として dp[i] = max(dp[i-1], dp[i-2] + nums[i])

空間を圧縮する場合は変数 prev1 / prev2 の 2 つだけで進められる

更新順に注意。current を計算してから prev2 = prev1、prev1 = current の順で代入する

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

関連レッスン

  • グリッド経路数 (Unique Paths)

    右と下にのみ進めるグリッドの上で、左上から右下に至る経路の総数を二次元 DP で数えます。

  • 単語分割可能か (Word Break)

    辞書にある単語の連結で対象文字列を構成できるかを判定する Word Break 問題を、DP で線形時間に近い計算量で解きます。

  • 第6章まとめクイズ — 動的計画法 (上級)

    編集距離、LIS、Kadane、House Robber、グリッド経路数、Word Break の理解度を確認する 4 択クイズです。

  • map と filter を組み合わせる

    配列に対して `map` と `filter` を組み合わせ、偶数だけを 2 倍した結果を返す関数を実装する。関数型プログラミングの基礎を学ぶ。

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

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

  • 配列サイズ固定の同型データの集まり
  • 変数データに名前をつけて参照する仕組み
  • 戻り値呼び出し元への返答を表す点線矢印
main.py
学習モード
エディタを読み込んでいます

メモ

隣り合わない最大値 (House Robber)

⌘S で保存