C++で範囲内の欠落している要素を検索する方法
この記事では、サイズ n の配列 arr[] と、範囲を示す開始値・終了値が与えられたときに、範囲内で欠落している要素を見つける方法を解説します。
問題の概要
与えられた範囲 [start, end] に含まれるべき整数のうち、配列 arr[] に存在しない要素をすべて見つけて出力するのが目的です。
入力例
arr[] = {4, 6, 3, 7}, start = 3, end = 8出力例
5, 8
説明
範囲は [3, 4, 5, 6, 7, 8] であり、配列は {4, 6, 3, 7} です。したがって、配列に存在しない範囲内の要素は 5 と 8 になります。
解決アプローチ
この問題は複数の方法で解くことができます。ここでは代表的な3つのアプローチを紹介します。
#アプローチ1: ソートと二分探索(lower_bound)を使う方法
最もシンプルな方法は、範囲の各要素が配列に存在するかを直接確認することです。まず配列をソートし、lower_bound を使って範囲の開始値に相当する位置を見つけます。その後、範囲の値と配列の要素を順に比較しながら、一致しない値(= 欠落している要素)を出力していきます。
実装例:
#include <bits/stdc++.h>
using namespace std;
void findMissingElements(int arr[], int n, int low, int high){
sort(arr, arr + n);
int* pointerVal = lower_bound(arr, arr + n, low);
int index = pointerVal - arr;
int i = index, x = low;
while (i < n && x <= high) {
if (arr[i] != x)
cout << x << " ";
else
i++;
x++;
}
while (x <= high)
cout<<x++<<" ";
}
int main(){
int arr[] = { 4, 6, 3, 7 };
int n = sizeof(arr) / sizeof(arr[0]);
int low = 3, high = 9;
cout<<"The missing elements are ";
findMissingElements(arr, n, low, high);
return 0;
}出力
The missing elements are 5 8 9
この方法の計算量は、ソートに O(n log n)、比較処理に O(n + 範囲の長さ) となります。
#アプローチ2: ブール配列を使う方法
次の方法は、ブール配列を活用するアプローチです。サイズ (end − start + 1) のブール配列を作成し、配列 arr[] の各要素 v について、v が範囲内であれば boolArray[v − start] を true に設定します。最後にブール配列全体を走査し、false のままになっているインデックスに対応する値(start + i)を出力すれば、それが欠落している要素です。
実装例:
#include <bits/stdc++.h>
using namespace std;
void findMissingElements(int arr[], int n, int start, int end){
bool boolArray[end - start + 1] = { false };
for (int i = 0; i < n; i++) {
if (start <= arr[i] && arr[i] <= end)
boolArray[arr[i] - start] = true;
}
for (int i = 0; i <= end - start; i++) {
if (boolArray[i] == false)
cout<<(start + i)<<"\t";
}
}
int main(){
int arr[] = { 4, 6, 3, 7 };
int n = sizeof(arr) / sizeof(arr[0]);
int low = 3, high = 9;
cout<<"The missing elements are ";
findMissingElements(arr, n, low, high);
return 0;
}出力
The missing elements are 5 8 9
この方法の計算量は O(n + 範囲の長さ) で、ソート不要のため高速に動作します。ただし、範囲が非常に大きい場合はメモリ消費に注意が必要です。
#アプローチ3: ハッシュテーブル(unordered_set)を使う方法
3つ目の方法は、ハッシュテーブルを利用するアプローチです。まず配列の全要素を unordered_set に挿入します。その後、範囲 [start, end] を順に走査し、セットに存在しない値を出力します。ハッシュセットによる検索は平均 O(1) で行えるため、効率的です。
実装例:
#include <bits/stdc++.h>
using namespace std;
void findMissingElements(int arr[], int n, int start, int end){
unordered_set<int> arrEle;
for (int i = 0; i < n; i++)
arrEle.insert(arr[i]);
for (int i = start; i <= end; i++)
if (arrEle.find(i) == arrEle.end())
cout<<i<<"\t";
}
int main(){
int arr[] = { 4, 6, 3, 7 };
int n = sizeof(arr) / sizeof(arr[0]);
int low = 3, high = 9;
cout<<"The missing elements are ";
findMissingElements(arr, n, low, high);
return 0;
}出力
The missing elements are 5 8 9
まとめ
C++で範囲内の欠落要素を検索するには、主に以下の3つの方法があります。
- ソート + lower_bound: 追加メモリが少なくて済むが、ソートに O(n log n) かかる。
- ブール配列: 計算量 O(n + 範囲の長さ) で高速だが、範囲の大きさに応じたメモリが必要。
- unordered_set(ハッシュセット): 実装がシンプルで、平均 O(n + 範囲の長さ) の計算量。
データの規模や範囲の広さ、メモリ制約に応じて、最適なアプローチを選択しましょう。
-
C++で配列要素の階乗の最大公約数(GCD)を求める方法
N個の要素を持つ配列Aが与えられたとき、配列内のすべての要素の階乗の最大公約数(GCD)を求めることを考えます。例えば、配列の要素が {3, 4, 8, 6} の場合、各要素の階乗は 3! = 6、4! = 24、8! = 40320、6! = 720 となり、これらのGCDは 6 になります。解法のポイントここで重要な数学的な性質があります。2つの数のGCDとは、両方の数を割り切る最大の数のことです。階乗の場合、小さい数の階乗は必ず大きい数の階乗を割り切ることができます。つまり、2つの階乗のGCDは、小さい方の数の階乗そのものになります。例えば、3! と 5! のGCDを考えると、3! =
-
Pythonのリストから欠けている要素(抜けている数値)を見つける方法
数値を含むリストがあるとき、その数値が連続しているかどうかを確認したり、リスト内の最大値を最終値として、その範囲の中で欠けている数値を特定したりすることができます。ここでは、代表的な2つのアプローチを紹介します。 range関数とmax関数を使う方法 forループと not in 演算子を組み合わせることで、指定した範囲の中に存在しない値をチェックできます。見つかった欠損値を新しいリストに追加していき、それを結果として取得します。 サンプルコード listA = [1,5,6, 7,11,14] # 元のリスト print(Given list : ,listA) # range と ma