C++で重複しない区間を作るための最小削除数を求めるアルゴリズム
問題概要
複数の区間(インターバル)のコレクションが与えられたとき、残りの区間同士が互いに重なり合わないようにするために、削除が必要な区間の最小数を求める問題です。
例えば、区間が [[1,2], [2,3], [3,4], [1,3]] であった場合、他のすべての区間が重複しない状態にするには [1,3] を削除すればよいため、出力は 1 となります。
解決のためのアプローチ
この問題は貪欲法(グリーディ法)を使うことで効率的に解くことができます。手順は以下の通りです。
- n := 配列のサイズとします
- n が 0 の場合は 0 を返します
- count := 1 で初期化します
- 区間の終了時刻に基づいて配列をソートします
- end := 最初の区間の終了時刻とします
- i を 1 から n - 1 まで繰り返します
- arr[i] の開始時刻が end 以上の場合:
- end := arr[i] の終了時刻に更新します
- count を 1 増加させます
- arr[i] の開始時刻が end 以上の場合:
- 最後に n - count を返します
このアプローチでは、終了時刻の早い区間から優先的に選ぶことで、後続の区間との重複を最小限に抑えることができます。
C++での実装例
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
static bool cmp(vector <int>& a, vector <int>& b){
return a[1] < b[1];
}
int eraseOverlapIntervals(vector<vector<int>>& arr) {
int n = arr.size();
if(!n)return 0;
int cnt = 1;
sort(arr.begin(), arr.end(), cmp);
int end = arr[0][1];
for(int i = 1; i < n; i++){
if(arr[i][0] >= end){
end = arr[i][1];
cnt++;
}
}
return n - cnt;
}
};
main(){
vector<vector<int>> v = {{1,2},{1,2},{1,2}};
Solution ob;
cout << (ob.eraseOverlapIntervals(v));
}入力
[[1,2],[1,2],[1,2]]
出力
2
コードの解説
この実装では、まず比較関数 cmp を使って各区間を終了時刻の昇順にソートしています。その後、最初の区間の終了時刻を基準として、以降の区間の開始時刻がこの基準以上であれば重複していないと判断し、カウントを増やしていきます。
最終的な答えは「全体の区間数 n」から「重複なく選べた区間数 cnt」を引いた値、つまり削除が必要な区間の数になります。
上記の入力例では、同じ区間 [1,2] が3つ存在するため、1つだけを残して残りの2つを削除する必要があり、出力は 2 となります。
計算量について見てみると、ソートに O(n log n)、その後の走査に O(n) かかるため、全体の時間計算量は O(n log n) となります。
-
C++で点集合の線対称(ラインリフレクション)を判定するアルゴリズム
問題概要2次元平面上にn個の点が与えられます。このとき、y軸に平行な直線で全ての点を鏡映(反射)した結果が、元の点集合と完全に一致するような直線が存在するかどうかを判定します。言い換えれば、ある直線を対称軸として全ての点を反転させたとき、反転後の点の集合が元の集合と同一になるかを確認する問題です。例えば、入力が points = [[1,1],[-1,1]] の場合を考えてみましょう。この場合、x = 0 の直線(y軸)を対称軸とすると、点 (1,1) は (-1,1) へ、(-1,1) は (1,1) へと移ります。点集合全体としては変化がないため、出力は true となります。解法のポイン
-
C++で解く対角トラバースII:リストのリストを対角順に出力する方法
問題の概要 「リストのリスト」である nums が与えられたとき、そのすべての要素を対角順(ダイアゴナルオーダー)に並べて出力するのがこの問題の目的です。 たとえば、次のような行ごとに長さの異なる配列(ジャグ配列)が入力として与えられた場合を考えてみましょう。 このとき、期待される出力は次のとおりです。 [1, 6, 2, 8, 7, 3, 9, 4, 12, 10, 5, 13, 11, 14, 15, 16] 解法のアプローチ この問題は、各要素を「値と座標のセット」として一旦記録し、対角線ごとの順序になるようにソートし直すことで解けます。具体的な手順は以下の通りです。 結果を格納す