Pythonで合計がkの倍数となる長さ2以上の部分リストを検出する方法
非負の整数からなるリスト nums と、正の整数 k が与えられたとします。このとき、要素の合計が k の倍数になる「長さ 2 以上の部分リスト(サブリスト)」が存在するかどうかを判定します。
たとえば、入力が nums = [12, 6, 3, 4]、k = 5 の場合、出力は True になります。これは、部分リスト [12, 3] を選ぶと合計が 15 となり、5 で割り切れるためです。
アルゴリズムの考え方
この問題は、累積和の剰余(mod k)を利用することで効率的に解けます。ポイントとなるのは次の性質です。
「2つの累積和の剰余が等しい場合、その間にある要素の合計は必ず k の倍数になる」
そこで、各インデックスにおける累積和を k で割った余りをハッシュマップに記録していき、同じ余りが再び現れたときに、そのインデックスの差が 2 以上であれば、条件を満たす部分リストが存在すると判断できます。
手順
sum = 0と初期化する- 空のマップ
mを作成し、m[0] = -1を設定する(リスト開始前の仮想インデックスを表す) - i を 0 から nums の長さ - 1 まで繰り返す:
sum += nums[i]sum %= ksumがmに既に存在する場合:i - m[sum] >= 2ならTrueを返す- 存在しない場合:
m[sum] = iを記録する
- ループが終了しても見つからなければ
Falseを返す
なお、初期値として m[0] = -1 を設定しておくことで、「リストの先頭から始まる部分リスト」も正しく扱えるようになります。
実装例
以下がPythonによる実装です。
class Solution:
def solve(self, nums, k):
sum = 0
m = {}
m[0] = -1
for i in range(0, len(nums)):
sum += nums[i]
sum %= k
if sum in m:
if i - m[sum] >= 2:
return True
else:
m[sum] = i
return False
ob = Solution()
nums = [12, 6, 3, 4]
k = 5
print(ob.solve(nums, k))
入力
[12, 6, 3, 4], 5
出力
True
計算量について
このアルゴリズムはリストを一度だけ走査するため、時間計算量は O(n) です。また、ハッシュマップに保存される剰余は最大でも min(n, k) 種類なので、空間計算量も O(min(n, k)) に抑えられます。すべての部分リストを列挙する総当たり法(O(n²) 以上)と比較して、はるかに効率的なアプローチといえます。
-
Pythonでリストの累積和(累積合計)を求める方法
この記事では、リストの累積和(累積合計)を求める問題の解決策について詳しく解説します。問題文あるリストが与えられたとき、各要素までの累積和を格納した新しいリストを作成する必要があります。例えば、[10, 20, 30, 40, 50] というリストが与えられた場合、出力は [10, 30, 60, 100, 150] となります。これは、各位置でそれ以前の要素をすべて足し合わせた値です。実装例それでは、実際の実装を見ていきましょう。# 累積和を求める関数 def Cumulative(l): new = [] cumsum = 0 for element in l:
-
Pythonで配列(リスト)の合計を求める方法をわかりやすく解説
この記事では、配列(リスト)の合計値を求めるという問題に対して、Pythonでの解決策とアプローチをわかりやすく解説します。 問題の定義 配列が入力として与えられたとき、その配列に含まれるすべての要素の合計を計算することを目標とします。 例えば、[1, 2, 3, 4, 5] という配列が与えられた場合、出力は 15 になります。 アプローチ1:ループを使った素朴な方法(総当たり法) 最も基本的な方法は、リストを先頭から順に走査し、各要素を合計用の変数に加算していくやり方です。手順は以下の通りです。 合計を格納する変数を 0 で初期化します。 for ループでリストの各要素を取り出し、順番に