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

C++で合計が0となる部分配列の存在を効率的に判定する方法

はじめに

この記事では、整数値からなるサイズ n の配列 arr[] が与えられたときに、合計が0となる部分配列(サブアレイ)が存在するかどうかを判定する方法を解説します。

具体的には、配列の中に「すべての要素の合計が0に等しい」連続した部分配列が含まれているかどうかを確認する問題です。

問題の例

入力: arr[] = {3, 1, -2, 1, 4, 5}

出力: Yes

説明:

部分配列 {1, -2, 1} の要素の合計は 1 + (-2) + 1 = 0 となり、条件を満たしています。このため答えは「Yes」となります。

解法アプローチ

1. 素朴な解法(全探索)

最もシンプルな方法は、考えられるすべての部分配列を列挙し、それぞれの要素の合計が0になるかどうかを確認することです。しかし、この方法では時間計算量が O(n²) になり、配列のサイズが大きくなると非効率です。

2. ハッシュを使った効率的な解法

より効率的なのがハッシング(ハッシュテーブル)を活用する方法です。このアイデアは「累積和(プレフィックスサム)」の性質に基づいています。

アルゴリズムの手順は以下の通りです。

  • 配列を先頭から走査し、現在のインデックスまでの累積和を計算します。
  • 同じ累積和が過去に出現している場合、その間の部分配列の合計は必ず0になります。
  • また、累積和自体が0になった場合も、先頭からの部分配列の合計が0であることを意味します。
  • 上記のどちらかに該当すれば true を返し、最後まで見つからなければ false を返します。

この手法を使えば、時間計算量 O(n)、空間計算量 O(n) で問題を解くことができます。

C++での実装例

#include <bits/stdc++.h>
using namespace std;

bool isSubArraySumZero(int arr[], int n) {
    
    unordered_set<int> sumHash;

    int currSum = 0;
    for (int i = 0 ; i < n ; i++) {
        
        currSum += arr[i];
        if (currSum == 0 || sumHash.find(currSum) != sumHash.end())
            return true;
        sumHash.insert(currSum);
    }
    return false;
}

int main() {
    
    int arr[] = { 3, 1, -2, 1, 4, 5 };
    int n = sizeof(arr)/sizeof(arr[0]);
    if (isSubArraySumZero(arr, n))
        cout<<"SubArray with sum equal to 0 exists in the array";
    else
        cout<<"No subarray exists";
    return 0;
}

出力結果

SubArray with sum equal to 0 exists in the array

まとめ

合計が0となる部分配列の存在確認は、累積和とハッシュセットを組み合わせることで線形時間で解決できます。ポイントは「同じ累積和が二度現れたら、その間の部分配列の合計は必ず0になる」という性質です。全探索による O(n²) の素朴な解法と比べて大幅に高速化できるため、実務やコーディング面接でも役立つテクニックとして覚えておきましょう。

  1. C++で厳密に増加する部分配列の最大和を求めるアルゴリズム

    問題の概要n 個の整数からなる配列が与えられたとき、その中に存在する「厳密に増加する(strictly increasing)部分配列」の中で、要素の合計が最大となるものを求めます。例として、次のような配列を考えてみましょう。[1, 2, 3, 2, 5, 1, 7]この配列には、厳密に増加している部分配列が3つ存在します。{1, 2, 3}{2, 5}{1, 7}それぞれの合計は 6、7、8 となり、この中で最大となるのは {1, 7} の合計 8 です。解き方の考え方この問題は、現在の部分配列の合計(current_sum)とこれまでの最大合計(max_sum)を追跡しながら配列を一度だけ

  2. C++を使って行列内で合計が最大の列を見つける方法

    ここでは、サイズ M × N の行列が与えられたときに、要素の合計が最大となる列を見つける方法を解説します。この問題では、難しいアルゴリズムを用いる必要はありません。行列を列方向に走査して各列の合計値を計算し、その合計が最大であれば、合計値と該当する列のインデックスを出力するというシンプルなアプローチで十分です。アルゴリズムの手順処理の流れは以下の通りです。1. 最大合計値を格納する変数 maxSum を INT_MIN で初期化し、列のインデックスを格納する index を -1 に設定します。2. 各列(0 ~ N-1)について、colSum 関数を使ってその列の要素の合計を計算します。3