Swift教室 Swift と競技プログラミングの教室

36. House Robber II

読了目安 約1分

DP / LeetCode 213 (Medium) — 円環版 House Robber。場合分けで直線の DP に帰着する。

この章の目次

問題

LeetCode 213. House Robber II(Medium / カテゴリ: DP)

House Robber と同じ設定で、今回は家が円形に並んでいます。 つまり最初の家と最後の家が隣り合っています。 隣接する家を選ばずに盗める金額の最大値を返してください。

考え方

ヒント 1

円形で増えた制約は「最初の家と最後の家を同時に盗めない」ことだけです。 「最初の家を使わない」場合と「最後の家を使わない」場合に分ければ、どちらも直線の House Robber になります。

ヒント 2

状態・遷移・初期条件は前問とまったく同じです。 答えは、先頭を除いた列と末尾を除いた列それぞれに直線版 DP を適用した結果の最大値です。 家が 1 軒だけのときは両方の列が空になるので、先に nums[0] を返します。

Swift 実装のポイント

  • nums.dropFirst()nums.dropLast()ArraySlice を返します。配列をコピーせずに部分列を扱えます。
  • 補助関数の引数型を ArraySlice<Int> にすると、両方のスライスをそのまま渡せます。
  • nums.count == 1 の場合分けを忘れると答えが 0 になります。
模範解答
Swift
class Solution {
    func rob(_ nums: [Int]) -> Int {
        if nums.count == 1 { return nums[0] }
        return max(robLine(nums.dropFirst()), robLine(nums.dropLast()))
    }

    private func robLine(_ houses: ArraySlice<Int>) -> Int {
        var prev = 0
        var cur = 0
        for x in houses {
            (prev, cur) = (cur, max(cur, prev + x))
        }
        return cur
    }
}

計算量: O(N)。