【C++】指定された要素を削除した後、配列からk個の最大値を見つける方法
問題の概要
この記事では、サイズnの整数型配列arr[]、サイズmの配列del[]、および整数kが与えられたときに、指定された要素を削除した後のk個の最大値を見つける方法を解説します。
具体的には、del[]に含まれるすべての要素をarr[]から削除し、残った配列の中から大きい方からk個の要素を出力します。なお、同じ値が複数存在する場合は、先に出現したインスタンスを削除するものとします。
例で理解しよう
入力 : arr[] = {3, 5, 1, 7, 9, 2}, del[] = {1, 9, 3}, k = 2
出力 : 7, 5説明:
要素を削除した後の配列arr[] : {5, 7, 2}
最大の2要素は 7 と 5。解法アプローチ①:ソートを使うシンプルな方法
最もシンプルな解決策は、まずarr[]からdel[]に存在するすべての要素を削除し、その後配列を降順にソートして、先頭のk個の要素を出力するというものです。
実装例
以下は、この解法の動作を示すC++プログラムです。
#include <bits/stdc++.h>
using namespace std;
void findKmaxElementDelArray(int arr[], int n, int del[], int m, int k){
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(arr[j] == del[i]){
arr[j] = INT_MIN;
break;
}
}
}
sort(arr, arr + n, greater<int>());
for (int i = 0; i < k; ++i) {
cout<<arr[i]<<" ";
}
}
int main(){
int array[] = { 3, 5, 1, 7, 9, 2 };
int m = sizeof(array) / sizeof(array[0]);
int del[] = { 1, 9, 3 };
int n = sizeof(del) / sizeof(del[0]);
int k = 2;
cout<<k<<" largest numbers after deleting the elements are ";
findKmaxElementDelArray(array, m, del, n, k);
return 0;
}出力結果
2 largest numbers after deleting the elements are 7 5
解法アプローチ②:ハッシュマップとヒープを使う方法
もうひとつのアプローチとして、ハッシュマップ(unordered_map)とヒープ(priority_queue)を組み合わせる方法があります。まず最大ヒープとハッシュマップを作成し、ハッシュマップにはdel[]配列のすべての要素を格納します。次に、ハッシュマップに存在しないarr[]の要素だけを最大ヒープに挿入します。最後に、ヒープからk個の要素を取り出して出力すれば完成です。
この方法では、削除対象の要素を実際に配列から取り除く代わりに、ハッシュマップによる照合で該当要素をスキップできるため、大規模なデータを扱う場合により効率的に処理できます。
実装例
#include <bits/stdc++.h>
using namespace std;
void findKmaxElementDelArray(int arr[], int n, int del[], int m, int k){
unordered_map<int, int> deleteElement;
for (int i = 0; i < m; ++i) {
deleteElement[del[i]]++;
}
priority_queue<int> maxHeap;
for (int i = 0; i < n; ++i) {
if (deleteElement.find(arr[i]) != deleteElement.end()) {
deleteElement[arr[i]]--;
if (deleteElement[arr[i]] == 0) deleteElement.erase(arr[i]);
}
else
maxHeap.push(arr[i]);
}
for (int i = 0; i < k; ++i) {
cout<<maxHeap.top()<<" ";
maxHeap.pop();
}
}
int main(){
int array[] = { 3, 5, 1, 7, 9, 2 };
int m = sizeof(array) / sizeof(array[0]);
int del[] = { 1, 9, 3 };
int n = sizeof(del) / sizeof(del[0]);
int k = 2;
cout<<k<<" largest numbers after deleting the elements are ";
findKmaxElementDelArray(array, m, del, n, k);
return 0;
}出力結果
2 largest numbers after deleting the elements are 7 5
まとめ
指定された要素を削除した後のk個の最大値を求める問題に対して、①削除後に降順ソートを行うシンプルな手法と、②ハッシュマップと最大ヒープを活用する効率的な手法の2つを紹介しました。データ量が多く、かつkが小さい場合は、ヒープを使ったアプローチの方が計算コストを抑えられる点で有利です。用途に応じて最適な方法を選択しましょう。
-
【C++】指定されたインデックスのN個のフィボナッチ数のGCDを効率的に求める方法
本記事では、指定された複数のインデックスに対応するN個のフィボナッチ数の最大公約数(GCD)を、C++で効率的に求める方法を解説します。 フィボナッチ数列と問題の概要 まずおさらいとして、フィボナッチ数列は「0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …」のように、直前の2つの項の和によって定義される数列です。インデックスは0から始まるため、0番目の要素は0、1番目の要素は1となります。 例えば、インデックス{2, 3, 4, 5}に対応するフィボナッチ数は{1, 2, 3, 5}であり、これらのGCDは1です。 鍵となる性質:GCD(Fibo(i), Fibo(j))
-
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! =