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

【C++】配列をサイズKのセグメントに分割し、すべてのセグメントにキーXが存在するか判定する方法

概要

要素数 N の配列 arr1[]、検索対象のキー X、およびセグメントサイズ K が与えられたとき、「配列をサイズ K ごとの区間(セグメント)に区切った場合に、そのすべてのセグメントにキー X が含まれているか」を判定するのが本記事の課題です。

入力例1

arr1[] = { 4, 6, 3, 5, 10, 4, 2, 8, 4, 12, 13, 4}
X = 4
K = 3

出力

Yes

この配列は、サイズ 3 の重なり合わないセグメントが 4 つ、すなわち {4, 6, 3}、{5, 10, 4}、{2, 8, 4}、{12, 13, 4} に分けられます。いずれのセグメントにも 4 が含まれているため、答えは「Yes」となります。

入力例2

arr1[] = { 22, 24, 57, 66, 35, 55, 77, 33, 24, 46, 22, 24, 26}
X = 24
K = 5

出力

Yes

{22, 24, 57, 66, 35}、{55, 77, 33, 24, 46}、{22, 24, 26} の 3 つのセグメントすべてに 24 が含まれているため「Yes」です。

入力例3

arr1[] = { 6, 9, 8, 13, 15, 4, 10}
X = 9
K = 2

出力

No

{6, 9}、{8, 13}、{15, 4}、{10} のうち、{8, 13} に 9 が含まれていないため「No」となります。

アルゴリズムの考え方

アプローチは非常にシンプルです。先頭からサイズ K ずつのセグメントを順に走査し、それぞれのウィンドウ内にキー X が存在するかどうかを確認します。

ポイントは、配列の長さ N が必ずしも K の倍数とは限らないことです。N を K で割り切れない場合、末尾に K より短い「端数のセグメント」が残るため、その最後のセグメントも忘れずにチェックする必要があります。

処理の流れを整理すると次のとおりです。

1. インデックス 0 から K 間隔でループを回し、各セグメント内で X を線形探索します。
2. あるセグメント内で X が 1 つも見つからなければ、即座に false を返します。
3. すべての完全なセグメントで X が見つかったら、N が K の倍数かどうかを確認します。
4. 倍数であれば true を返し、そうでなければ残りの端数部分(最後のセグメント)に対しても同様に探索を行います。

C++での実装例

以下が上記アプローチの実装です。

// C++コード:配列の各セグメント(サイズK)に
// 検索キー x が含まれるかどうかを判定する
#include <bits/stdc++.h>
using namespace std;
bool findxinkindowSize1(int arr1[], int X, int K, int N){
   int i;
   for (i = 0; i < N; i = i + K) {
      // インデックス i から始まるセグメント内で X を探索
      int j;
      for (j = 0; j < K; j++)
         if (arr1[i + j] == X)
            break;
      // ループが途中で抜けなかった場合(Xが見つからなかった場合)
      if (j == K)
         return false;
   }
   // N が K の倍数の場合
   if (i == N)
      return true;
   // N が K の倍数でない場合、最後の端数セグメントを確認
   int j;
   for (j=i-K; j<N; j++)
      if (arr1[j] == X)
         break;
   if (j == N)
      return false;
   return true;
}
// main関数
int main(){
   int arr1[] = { 4, 6, 3, 5, 10, 4, 2, 8, 4, 12, 13, 4 };
   int X = 4, K = 3;
   int N = sizeof(arr1) / sizeof(arr1[0]);
   if (findxinkindowSize1(arr1, X, K, N))
      cout << "Yes" << endl;
   else
      cout << "No" << endl;
   return 0;
}

出力結果

Yes

計算量について

このアルゴリズムでは、配列の各要素を高々 1 回ずつ調べるため、時間計算量は O(N) となります。また、追加のメモリをほとんど使用しないため、空間計算量は O(1) です。配列全体を 1 回の走査で判定できる、非常に効率的な手法といえます。

まとめ

配列をサイズ K のセグメントに区切り、各セグメントにキー X が含まれるかを判定する問題は、単純な二重ループによる線形探索で解決できます。実装上の注意点は「N が K の割り切れない場合の末尾セグメントの扱い」であり、これを正しく処理することで境界条件のバグを防げます。計算量 O(N)・空間 O(1) と効率的なので、実務でもそのまま活用できるパターンです。

  1. C++で配列内に存在するキーKの出現確率を求める方法

    問題概要サイズ「n」の配列が与えられ、その配列内に指定された要素 k が存在する場合に、その出現確率を求めることが課題です。配列の要素数と等しい「n」まで配列全体を走査し、指定された要素(キー)「k」を検索します。要素が配列内に存在する場合はその確率を計算して返し、存在しない場合は 0 を出力します。入力arr[] = { 1, 2, 3, 4, 5, 6} K = 5出力配列におけるキー 5 の確率 : 0.166入力arr[] = { 1,2,3,4,5,6,7 } K = 8出力配列におけるキー 8 の確率 : 0考え方上記はサイズ 7 の配列とキー 2 を例とした説明です。この場合、配

  2. 配列が高さnのBSTを表せるかどうかをC++で判定する方法

    サイズnの配列が与えられたとき、その配列が高さnの二分探索木(BST)を表すことができるかどうかを判定する問題について解説します。ここで「高さn」とは、根から葉までの最長パスがn個のノードで構成されることを意味し、つまり配列の各要素が木の各レベルに1つずつ対応することを指します。 問題の理解 BSTのルールに従って要素を挿入していくとき、配列の順序通りに挿入した結果、高さがちょうどn(要素数と同じ)になるかどうかを確認します。これは、配列の各要素が前の要素の左または右の子として挿入され、一度も同じレベルに複数のノードが配置されないことを意味します。 例として以下の2つの配列を考えます: