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

16. Subarray Sum Equals K

読了目安 約2分

HashMap / LeetCode 560 (Medium) — 累積和の出現回数を辞書に持ち、和が k の部分配列を数える。

この章の目次

問題

LeetCode 560. Subarray Sum Equals K(Medium / カテゴリ: HashMap)

整数の配列 nums と整数 k が与えられます。 連続する部分配列のうち、和がちょうど k になるものの個数を返します。 要素に負の数を含むので、和の単調性を使う解法は使えません。

考え方

ヒント 1

先頭からの和を累積和と呼びます。 区間の和は 2 つの累積和の差で表せるので、「和が k の区間」は「差が k になる累積和のペア」と同じです。

ヒント 2

左から走査しながら、これまでに現れた累積和の出現回数を辞書で持ちます。 いまの累積和 sum に対して、過去に sum - k が現れた回数だけ、ここで終わる部分配列が見つかります。 先頭から始まる区間も数えるため、辞書は [0: 1] から始めます。

Swift 実装のポイント

  • 辞書は [Int: Int] で「累積和 → 出現回数」を持ちます。初期値は [0: 1] です。
  • 回数の参照は freq[sum - k, default: 0] で「なければ 0」を短く書けます。
  • 「数えてから登録」の順序を守ります。逆にすると k == 0 のとき長さ 0 の区間まで数えてしまいます。
模範解答
Swift
class Solution {
    func subarraySum(_ nums: [Int], _ k: Int) -> Int {
        var count = 0
        var sum = 0
        var freq: [Int: Int] = [0: 1]  // 累積和 → 出現回数
        for num in nums {
            sum += num
            count += freq[sum - k, default: 0]
            freq[sum, default: 0] += 1
        }
        return count
    }
}

計算量: O(n)(配列を 1 回走査し、辞書の操作は平均 O(1) です)。