1. nums=[1,1,1], k=2 -> 2
  2. nums=[1,2,3], k=3 -> 2
  3. nums=[1,-1,1,-1,1], k=0 -> 6
  4. nums=[3,4,7,2,-3,1,4,2], k=7 -> 4
  5. nums=[1], k=0 -> 0
  6. nums=[0,0,0], k=0 -> 6
コース一覧
コンピューターサイエンス上級:アルゴリズムとデータ構造
部分配列の和 = k の個数

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

探索、ソート、木、グラフ、動的計画法、貪欲法など、競技プログラミングや技術面接で問われる高度なアルゴリズムとデータ構造を学べるコースです。基本的な 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分

部分配列の和 = k の個数

何本の区間を、何回足すことになるのか

連続する部分配列のうち、和が k になるものが何本あるかを数えます。まず、区間そのものが何本あるかを数えてみます。

JavaScript

let ranges = 0; for (let i = 0; i < nums.length; i++) { for (let j = i; j < nums.length; j++) ranges += 1; } // 要素 8 個で 36 本、1 万個なら約 5000 万本

区間を数えるだけならこれで済みますが、1 本ごとに和を出す必要があります。左端を決めて右へ伸ばしながら足していけば、1 本あたりの足し算は 1 回で済みます。それでも 1 万個の配列で 5000 万回です。

同じ足し算を、何度もやり直している

[3, 4, 7, 2] で、左端が先頭の区間と、1 つ右にずらした区間を並べてみます。

  • 左端が 3 — 3、3+4、3+4+7、3+4+7+2
  • 左端が 4 — 4、4+7、4+7+2

4+7 は両方に出てきます。左端をずらすたびに、その右側の足し算をもう一度やり直しているわけです。

やり直しを消す方法があります。先頭からの和を 1 本だけ持っておきます。

先頭から何個目まで0 個1 個2 個3 個4 個
足した値なし33, 43, 4, 73, 4, 7, 2
和0371416

4 と 7 の区間の和は 14 - 3 で 11 です。どの区間の和も、右端までの和から左端の手前までの和を引くだけで出ます。足し算はもう終わっていて、残るのは引き算 1 回だけになりました。

1 周で数えるために、何を覚えておけばよいか

右端を 1 つずつ右へずらしながら考えます。右端までの和を S とすると、和が k になる区間の左端は、S - k という和で終わっている位置です。

つまり毎回の問いは「S - k という和が、これまでに何回出てきたか」になります。前回は「出たかどうか」だけで足りましたが、今回は回数が要ります。区間が何本あるかを数える問題だからです。

覚えておくのは、これまでに出た先頭からの和と、それぞれが何回出たか。右端を 1 つ進めるたびに 1 回問い合わせて、返ってきた回数をそのまま答えに足していきます。配列を歩くのは 1 周だけです。

まだ何も足していない状態も、1 回に数える

[3, 4] で k = 7 のときを追ってください。右端が 4 の位置で S は 7、S - k は 0 です。和が 0 で終わっている位置は、まだ 1 つも足していない先頭の状態しかありません。ここを数に入れておかないと、配列の先頭から始まる区間が丸ごと数え落とされます。

もう 1 つ、和が k を超えたら左端を縮める、という書き方は今回使えません。負の数が混ざっていると、右へ伸ばした先で和が減ることがあるからです。先頭からの和で考えるかぎり、負の数も 0 もそのまま扱えます。

要件

  1. 累積和 + hashmap を使い O(n) で実装する
  2. 配列に負の数や 0 が含まれても正しく動作すること
  3. 戻り値は部分配列の個数 (int)

入出力例

subarraySumEqualsK([1,1,1], 2) → 2 subarraySumEqualsK([1,2,3], 3) → 2 subarraySumEqualsK([1,-1,1,-1,1], 0) → 6 subarraySumEqualsK([3,4,7,2,-3,1,4,2], 7) → 4 subarraySumEqualsK([1], 0) → 0 subarraySumEqualsK([0,0,0], 0) → 6

ヒント

`seen[0] = 1` を最初に入れておくと、`nums[0..j]` の和がちょうど `k` のケースが拾える

走査中: `prefix += v` してから `count += seen.get(prefix - k, 0)`、その後で `seen[prefix]` を 1 増やす

登録順が逆になるとカウントがずれるので、必ず「count 更新 → seen 更新」の順序を守る

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

関連レッスン

  • 最長連続部分列

    整数配列を `set` に入れて、連続する整数で最も長いシーケンスの長さを `O(n)` で求める。

  • 集合の積 (intersection)

    2 つの整数配列の共通要素 (集合の積) を `set` で求めて、重複なしの昇順リストで返す。

  • 第4章まとめクイズ

    ハッシュとセットの計算量・性質・使いどころを 4 択クイズで総点検する。

  • グラフ BFS で連結成分サイズを求める

    幅優先探索 (BFS) を使って、指定した頂点を含む連結成分のノード数を返す関数を実装する。

main.py
学習モード
エディタを読み込んでいます

メモ

部分配列の和 = k の個数

⌘S で保存