Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで総和がkで割り切れる連続部分列の個数を求めるプログラム

問題の概要

配列 nums と整数 k が与えられたとき、「要素の総和が k で割り切れる」連続した部分列(サブ配列)の個数を求める問題です。

例として、k = 3、nums = [1, 2, 3, 4, 1] という入力を考えてみましょう。この場合、条件を満たす部分列は [3]、[1, 2]、[1, 2, 3]、[2, 3, 4] の 4 つであるため、出力は 4 となります。

アルゴリズムの考え方

この問題は「累積和」と「剰余(モジュロ)」を組み合わせることで効率的に解けます。ポイントは次の通りです。

  • 先頭から順に累積和を計算し、その値を k で割った余りを記録していきます。
  • 異なる位置で同じ余りの累積和が現れた場合、その間にある部分列の総和は必ず k の倍数になります。
  • したがって、各余りがこれまで何回出現したかを数えておき、同じ余りが出るたびに「それまでの出現回数」を答えに加算すればよいことになります。
  • x[0] を最初に 1 にしておくのは、「先頭から始まる部分列」も正しくカウントできるようにするためです(空の接頭辞を考慮しています)。

解法の手順

  • 長さ k の配列 x を用意し、すべての要素を 0 で初期化します
  • x[0] := 1 と設定します
  • カウンタ r と累積和 s を 0 で初期化します
  • nums の各要素 elem に対して、以下を繰り返します
    • s := (s + elem) mod k で s を更新します
    • r := r + x[s] で答えに加算します
    • x[s] := x[s] + 1 で出現回数を記録します
  • 最終的な r を返します

実装例(Python)

理解を深めるために、実際のコードを見てみましょう。

def solve(k, nums):
   x = [0]*k
   x[0] = 1
   r=s=0
   for elem in nums:
      s = (s+elem) % k
      r += x[s]
      x[s] += 1
   return r

k = 3
nums = [1,2,3,4,1]
print(solve(k, nums))

入力

3, [1,2,3,4,1]

出力

4

計算量

配列 nums を一度だけ走査するため、時間計算量は O(n) です。また、余りごとの出現回数を格納する配列が必要なため、空間計算量は O(k) となります。すべての部分列を素朴に調べる O(n²) の方法に比べて大幅に高速に動作します。

  1. Pythonで数の偶数の約数の合計を求めるプログラムの実装方法

    本記事では、以下の問題文に対する解決策について学びます。問題文整数 n が与えられたとき、その数の偶数の約数(偶因子)の合計を求めることが課題です。この問題を解くには、まず奇数の約数をすべて除外する必要があります。入力された数が奇数の場合、偶数の約数は一つも存在しないため、直接 0 を返します。そうでない場合は、以下のコードで示すアプローチに従います。アルゴリズムの考え方このアプローチでは素因数分解を活用します。約数の合計は「各素因数の冪乗の和の積」として表せるという性質を利用します。偶数の約数のみを対象とするため、素因数 2 の部分については 20(つまり 1)を除外し、21 以降の項だけを

  2. Pythonで数の因子の最小合計を求めるプログラム|素因数分解の考え方

    本記事では、与えられた整数について、積が元の数と等しくなる因子の組み合わせの中から合計が最小となる値を求める方法を、Pythonのコード例とともに解説します。 問題定義 入力として1つの整数が与えられます。この数を複数の因子の積として表したとき、因子の合計が最小になるケースを求めてください。 すべての因子の組み合わせを網羅的に調べて合計を比較する方法もありますが、実はもっとシンプルで効率的なアプローチが存在します。 考え方:素因数の合計が最小になる 鍵となるのは次の性質です。積が一定の値になるとき、因子の合計が最小になるのは、すべての因子を素数まで分解した場合(素因数分解した場合)です。