C++で指定された要素を削除した後の最大値を求める方法
問題概要
サイズnの整数型配列arr[]と、削除したい要素を格納したサイズmの配列del[]が与えられます。求めたいのは、arr[]からdel[]に含まれる要素をすべて取り除いた後に残る、最大の要素の値です。
なお、削除対象の要素が配列内に複数存在する場合でも、削除するのは最初に出現した1つだけである点に注意してください。
入出力例
入力 : arr[] = {3, 5, 1, 7, 9, 2}, del[] = {1, 9, 3}
出力 : 7
解説:
要素を削除した後の配列 arr[] : {5, 7, 2}
この配列の最大値は 7
解法1: ソートを利用するシンプルなアプローチ
最も分かりやすいのは、以下の手順で処理を行う方法です。
- arr[]の各要素について、del[]に同じ値が存在するかを確認する。
- 存在すれば、その要素(最初のインスタンス)をINT_MAXで上書きし、「削除済み」の目印にする。
- 配列全体を昇順にソートする。
- ソート後の配列において、削除済み要素(INT_MAX)を除いた末尾の要素、すなわちarr[n-m-1]が答えとなる。
削除判定にO(n×m)、ソートにO(n log n)を要するため、全体の計算量はO(n×m + n log n)です。
実装例
#include <bits/stdc++.h>
using namespace std;
int findMaxElementDelArray(int arr[], int n, int del[], int m){
// 削除対象の要素をINT_MAXで上書き(最初の1つだけ)
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(arr[j] == del[i]){
arr[j] = INT_MAX;
break;
}
}
}
sort(arr, arr + n);
return arr[(n - m - 1)];
}
int main(){
int array[] = { 3, 5, 1, 7, 9, 2 };
int n = sizeof(array) / sizeof(array[0]);
int del[] = { 1, 9, 3 };
int m = sizeof(del) / sizeof(del[0]);
cout<<"削除後の最大要素は "<<findMaxElementDelArray(array, n, del, m);
return 0;
}
出力
削除後の最大要素は 7
解法2: ハッシュマップを利用する効率的なアプローチ
より高速に処理したい場合は、unordered_map(ハッシュマップ)を活用しましょう。手順は次のとおりです。
- del[]の全要素をハッシュマップdelMapに登録し、各値の出現回数をカウントしておく。
- arr[]を先頭から走査し、各要素がdelMapに存在するかを確認する。
- 存在する場合は削除対象なので、対応するカウントを1減らす。カウントが0になったらキーごと削除する。
- 存在しない場合は有効な要素なので、現在の最大値maxValと比較し、大きければ更新する。
- 走査が終わった時点のmaxValが、削除後の配列における最大値となる。
ハッシュマップへの検索・挿入は平均O(1)で行えるため、この方法の計算量はO(n + m)となり、解法1より大幅に高速です。
実装例
#include <bits/stdc++.h>
using namespace std;
int findMaxElementDelArray(int arr[], int n, int del[], int m){
unordered_map<int, int> delMap;
// 削除対象の要素を出現回数付きで登録
for (int i = 0; i < m; ++i) {
delMap[del[i]]++;
}
int maxVal = INT_MIN;
for (int i = 0; i < n; ++i) {
if (delMap.find(arr[i]) != delMap.end()) {
// 削除対象ならカウントを減らし、0になったら消す
delMap[arr[i]]--;
if (delMap[arr[i]] == 0)
delMap.erase(arr[i]);
}
else
maxVal = max(maxVal, arr[i]);
}
return maxVal;
}
int main(){
int array[] = { 3, 5, 1, 7, 9, 2 };
int n = sizeof(array) / sizeof(array[0]);
int del[] = { 1, 9, 3 };
int m = sizeof(del) / sizeof(del[0]);
cout<<"削除後の最大要素は "<<findMaxElementDelArray(array, n, del, m);
return 0;
}
出力
削除後の最大要素は 7
まとめ
指定された要素を削除した後の最大値を求める問題では、ソートを使う方法がシンプルで理解しやすい一方、計算量はO(n×m + n log n)になります。ハッシュマップを使えば削除対象の判定を高速化でき、全体をO(n + m)で処理可能です。データ量が多い場合やパフォーマンスが重要な場面では、ハッシュマップを活用するアプローチを選ぶとよいでしょう。
-
C++で指定された差分を持つペアを見つける方法
はじめに 配列 A に n 個の異なる要素が格納されているとします。この配列から、2つの要素 x と y の差が指定された値 d と一致するようなペア (x, y) をすべて見つける必要があります。 例として、配列が A = [10, 15, 26, 30, 40, 70]、指定された差分が 30 である場合を考えます。このとき、該当するペアは (10, 40) と (40, 70) です。 解法:ツーポインタ法 この問題は、配列が昇順にソートされていることを前提とすれば、ツーポインタ(二重インデックス)法を使って効率的に解くことができます。まず、1つ目のポインタ「i」を先頭の要素に、2つ目の
-
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! =