【C++解説】max−min ≤ K を満たすための配列からの最小削除数を求めるアルゴリズム
問題文
N個の整数と値Kが与えられたとき、残りの要素について Amax − Amin ≤ K が成り立つようにするために削除が必要な要素の最小個数を求めます。要素を削除した後の Amax(最大値)と Amin(最小値)は、残った要素の中から判断します。
例
配列 arr[] = {1, 3, 4, 9, 10, 11, 12, 17, 20}、k = 4 の場合、出力は 5 となります。
- 配列の先頭から 1、3、4 を削除する
- 配列の末尾から 17 と 20 を削除する
- 最終的な配列は {9, 10, 11, 12} となり、12 − 9 ≤ 4 を満たす
アルゴリズム
- 与えられた要素をソートします。
- 貪欲法の考え方では、最小値または最大値のいずれかを削除し、その都度 Amax − Amin ≤ K が成立しているかを確認するのが最善です。削除の組み合わせは複数考えられるため、それらすべてを検討する必要があります。
- 削除の方法は「最小値を削除する」か「最大値を削除する」の2通りです。削除後に残る要素のインデックス範囲を (i…j) とし、初期状態では i = 0、j = n−1、削除数は 0 から始めます。
- a[j] − a[i] > k の場合にのみ要素を削除します。削除方法は (i+1…j) または (i…j−1) の2通りあり、このうち結果が最小となるものを採用します。重複計算を避けるため、メモ化(DPテーブル)を利用しています。
C++実装例
#include <bits/stdc++.h>
#define MAX 100
using namespace std;
int dp[MAX][MAX];
int removeCombinations(int *arr, int i, int j, int k) {
if (i >= j) {
return 0;
} else if ((arr[j] - arr[i]) <= k) {
return 0;
} else if (dp[i][j] != -1) {
return dp[i][j];
} else if ((arr[j] - arr[i]) > k) {
dp[i][j] = 1 + min(removeCombinations(arr, i +
1, j, k),
removeCombinations(arr, i, j - 1,k));
}
return dp[i][j];
}
int removeNumbers(int *arr, int n, int k){
sort(arr, arr + n);
memset(dp, -1, sizeof(dp));
return n == 1 ? 0 : removeCombinations(arr, 0, n - 1,k);
}
int main() {
int arr[] = {1, 3, 4, 9, 10, 11, 12, 17, 20};
int n = sizeof(arr) / sizeof(arr[0]);
int k = 4;
cout << "Minimum numbers to be removed = " <<
removeNumbers(arr, n, k) << endl;
return 0;
}上記のプログラムをコンパイルして実行すると、次の出力が得られます。
出力
Minimum numbers to be removed = 5
まとめ
本問題は、ソート後の配列に対して「最小値を取り除く」か「最大値を取り除く」かを選択しながら再帰的に探索することで解けます。メモ化再帰(動的計画法)を組み合わせることで、同じ状態 (i, j) に対する再計算を防ぎ、効率的に最小削除数を求めることができます。
-
C++で配列の全要素を同じ値にするための最小削除操作数を求めるアルゴリズム
問題概要n個の要素からなる配列が与えられます。要素には重複が含まれる場合があります。この配列から任意の数の要素を削除できるとき、すべての要素を同じ値にするために必要な最小の削除数を求めるのが課題です。例として、次の配列を考えてみましょう。arr[] = {10, 8, 10, 7, 10, -1, -4, 12}この場合、最も多く出現している「10」以外の5つの要素を削除すれば、配列の全要素を10で統一できます。つまり、答えは5回の削除となります。解法の考え方この問題の鍵となるのは、「削除する量を最小化する = 残す要素の数を最大化する」という発想です。全要素を同じ値にするためには、必ずどれか
-
PythonでGCDを大きくするために必要な配列からの最小削除数を求めるアルゴリズム
N個の整数で構成されるリストが与えられ、残りの数値のGCD(最大公約数)が、元のN個すべてのGCDよりも大きくなるようにするには、最低何個の数値を取り除けばよいでしょうか。この記事では、その最小削除数を効率よく求めるアルゴリズムをPythonで解説します。 たとえば、入力が [6, 9, 15, 30] の場合、出力は 2 になります。初期のGCDは 3 ですが、6 と 9 を削除すると残りは 15 だけとなり、GCDは 15。これは 15 > 3 を満たすためです。 解法のポイント まず配列全体のGCDを g として求め、各要素を g で割って正規化します。正規化後の配列全体のGCDは