【Python】合計がターゲット値と一致するサブリストの個数を効率的に求める方法
数値のリスト nums とターゲット値 target が与えられたとき、要素の合計が target と一致するサブリスト(連続する部分列)がいくつ存在するかを求める問題について解説します。
たとえば、nums = [3, 0, 3]、target = 3 という入力の場合、答えは 4 になります。これは、合計が 3 になるサブリストとして [3]、[3, 0]、[0, 3]、[3] の 4 つが存在するためです。
解法のアプローチ:累積和とハッシュマップ
すべてのサブリストを総当たりで調べると O(n²) の時間がかかりますが、累積和(プレフィックスサム)と辞書(ハッシュマップ)を組み合わせることで、O(n) で効率的に解くことができます。
考え方はシンプルです。先頭から現在位置までの累積和を s とすると、「現在の累積和 − target」が過去のいずれかの時点の累積和と一致していれば、その間の区間の合計は target と一致することになります。そこで、各累積和の出現回数を辞書に記録しておき、一致するたびにその回数を答えに加算します。
アルゴリズムの手順
temp:累積和の出現回数を記録する空のマップ(辞書)を用意するtemp[0] := 1:初期状態(累積和 0)を 1 回として登録するs := 0(累積和)、ans := 0(答え)で初期化する- i を 0 から nums のサイズ未満まで繰り返す:
s := s + nums[i]で累積和を更新するcomp := s - targetを計算するcompがtempに存在すれば、ans := ans + temp[comp]を実行するtemp[s] := temp[s] + 1で現在の累積和を記録する
ansを返す
Python実装コード
from collections import defaultdict
class Solution:
def solve(self, nums, target):
temp = defaultdict(int)
temp[0] = 1
s = 0
ans = 0
for i in range(len(nums)):
s += nums[i]
comp = s - target
if comp in temp:
ans += temp[comp]
temp[s] += 1
return ans
ob = Solution()
nums = [3, 0, 3]
target = 3
print(ob.solve(nums, target))入力
[3, 0, 3], 3
出力
4
まとめ
この手法では、リストを一度走査するだけで答えが得られるため、時間計算量は O(n) に抑えられます。また、0 や負の数が含まれるリストでも正しく動作します。defaultdict(int) を使うことで、キーが存在しない場合の初期化処理も簡潔に書ける点がポイントです。「Subarray Sum Equals K」など、競技プログラミングやコーディング面接で頻出の定番テクニックなので、ぜひ覚えておきましょう。
-
Pythonプログラムで数の偶数の約数の合計を求める方法
この記事では、以下の問題文に対する解決策について詳しく解説します。 問題文:ある数が与えられたとき、その数のすべての偶数の約数(因子)の合計を求めて表示します。 アプローチ まず、与えられた数が奇数であるかどうかを確認します。奇数には偶数の約数が存在しないため、その場合は 0 を返します。 数が偶数である場合は、実際の計算に進みます。ここでのポイントは、20(つまり1)以外のすべての項を掛け合わせることで、偶数の約数の合計が得られるという点です。 偶数の約数からすべての奇数を取り除くために、20 に相当する「1」を無視します。この処理を行うことで、残るのは偶数の約数のみとなります。なお、2 は
-
Pythonで数の奇数の約数(奇因子)の合計を求めるプログラム
この記事では、「整数 n が与えられたとき、その数の奇数の約数(奇因子)の合計を求める」という問題の解き方を解説します。 問題文 整数 n が入力として与えられます。求めるのは、n の奇数の約数をすべて足し合わせた値です。 例えば n = 27 の場合、約数は 1, 3, 9, 27 のすべてが奇数であるため、合計は 1 + 3 + 9 + 27 = 40 となります。 アプローチのポイント この問題で最初に行うべきは、偶数の約数をすべて除外することです。 偶数の約数を取り除くには、n が 2 で割り切れなくなるまで繰り返し 2 で割ります。この操作によって n から 2 の因数が完全に