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

C++で合計がnとなる連続する整数列の個数を数えるプログラム

問題概要

ある整数 n が与えられたとき、合計がちょうど n になる「正の連続する整数からなるリスト」の個数を求めます。

例えば、入力が n = 15 の場合、出力は 4 になります。条件を満たすリストは次の4つです。

  • [1, 2, 3, 4, 5]
  • [4, 5, 6]
  • [7, 8]
  • [15]

解法のアプローチ(スライディングウィンドウ)

この問題はスライディングウィンドウ(尺取り法)を使うことで効率的に解けます。区間 [begin, end] 内の合計を管理しながら、ウィンドウを伸縮させていくのがポイントです。

具体的な手順は以下の通りです。

  1. begin := 1end := 1x := (n + 1) / 2 で初期化します。
  2. sum := 0 とします。
  3. end <= x の間、以下を繰り返します。
    • sum := sum + end としてウィンドウを右に広げます。
    • sum >= n の間、以下を繰り返します。
      • sum == n であれば、カウントを1増やします。
      • sum := sum - begin として先頭を取り除き、begin を1増やします。
    • end を1増やします。
  4. 最後に count + 1 を返します。これは単一要素のリスト [n] 自身を答えに含めるためです。

なお、探索範囲を (n + 1) / 2 までに絞れるのは、2つ以上の連続する正の整数の和が n になるとき、その最大値は高々 (n+1)/2 であるためです。これにより無駄な探索を省けます。

C++での実装例

#include <iostream>
using namespace std;

int solve(int n) {
    int begin = 1, end = 1, x = (n + 1) / 2, count = 0;
    long int sum = 0;
    while (end <= x) {
        sum += end;
        while (sum >= n) {
            if (sum == n)
                count++;
            sum -= begin;
            begin++;
        }
        end++;
    }
    return count + 1;
}

main() {
    cout << (solve(15));
}

入力

15

出力

4

計算量

このアルゴリズムの時間計算量は O(n)、空間計算量は O(1) です。各要素の追加・削除がそれぞれ高々1回ずつ行われるため、全体でも線形時間で処理が完了します。

  1. C++でXとの合計がフィボナッチ数になるノードを数える方法

    各ノードに数値の重みが割り当てられた二分木が与えられます。この記事の目的は、「ノードの重み + X」の計算結果がフィボナッチ数となるノードの個数を求めることです。フィボナッチ数列とは、0, 1, 1, 2, 3, 5, 8, 13… のように続く数列で、n番目の数は(n−1)番目と(n−2)番目の数の和になります。たとえば重みが13であればフィボナッチ数に該当するため、そのノードはカウント対象となります。入力例1temp = 1 の場合。値を入力すると、以下のような木が構成されます。出力Count the nodes whose sum with X is a Fibonacci number

  2. Pythonで二分木の合計がkとなるパスの数を数える方法

    問題の概要 二分木と値 k が与えられたとき、あるノードからその子孫へ向かうパスのうち、通過するノードの値の合計がちょうど k と一致するものがいくつ存在するかを求める問題です。 例えば、次のような二分木を考えてみましょう。 このとき k = 5 であれば、出力は 2 となります。条件を満たすパスは [2, 3] と [1, 4] の2つだからです。 解き方のアプローチ:累積和(prefix sum)の活用 この問題は「累積和(prefix sum)」というテクニックを使うことで、全ノードを一度だけ訪問する効率的なアルゴリズムとして解けます。考え方の手順は以下の通りです。 count:マッ