1. 分割統治の概要
分割統治法は、サイズ N の問題を、互いに独立しており、元の問題と同じ性質を持つ K 個の小さなサブ問題に分解することです。副問題の解決策を見つけると、元の問題の解決策が得られます。
1.1 基本的な考え方
ある問題を解くとき、その問題は大量のデータを扱わなければならない場合や、解決プロセスが非常に複雑であるため、直接解決法では時間がかかるか、直接解決することができません。この種の問題の場合、最初に問題をいくつかのサブ問題に分解し、これらのサブ問題の解決策を見つけてから、それらを組み合わせて問題全体の解決策を得る適切な方法を見つけることがよくあります。これらのサブ問題がまだ大きすぎて解決できない場合は、解決策が直接見つかるまで、いくつかの小さなサブ問題に分割することができます。これが分割統治戦略の基本的な考え方です。一般に、二分法も使用されます。
二分法: 分割統治戦略を使用して問題を解決する場合、必要な時間は分解後の部分問題の数、部分問題のサイズなどの要因によって異なり、二分法がよく使用されます。シンプルで均一な特性を持っているため、二分探索などの効率的な方法です。
1.2 解決策の手順
分割統治によって問題を解決する一般的な手順は次のとおりです。
(1) 分解。解決する問題をいくつかの小規模な同様の問題に分割します。
(2) サブ問題が十分に小さく分割されている場合は、より単純な方法で解決します。
(3) マージ 元の問題の要件に従って、サブ問題の解がレイヤーごとにマージされ、元の問題の解が形成されます。
1.3 特定のアルゴリズム
{
//开始
if(1、问题不可分)
2、返回问题解;
else
{
3、从原问题中划分出含一半运算对象的子问题1;
4、递归调用分治法过程,求出解1;
5、从原问题中划出含另一半运算对象的子问题2;
6、递归调用分治法过程,求出解2;
7、将解1、解2组合成整个问题的解;
}
}//结束
1.4 応用シナリオ
分割統治戦略を使用して解決される問題には、通常、次の特徴があります。
1. 元の問題は複数の下位問題に分解できます。元の問題と比較すると、これらの副問題は規模が縮小されているだけであり、その構造と解決方法は元の問題と同じまたは類似しています。
2. 元の問題の分解プロセスでは、部分問題が再帰的に解決されます。再帰には終了条件が必要なため、分解された部分問題のサイズが十分に小さい場合は、直接解決できるはずです。
3. 各部分問題を解決して解決策を取得した後、特定の方法または方法で元の問題の解決策を組み合わせたり構築したりできる必要があります。
分割統治戦略では、部分問題と元の問題の構造と解決策が類似しているため、分割統治法で解決される問題のほとんどは次の形式を採用していることを見つけるのは難しくありません。再帰の。マージ ソート、クイック ソート、ヒープ ソートなどのさまざまなソート方法には、分割統治の考え方があります。さらに、次の問題も分割統治戦略で解決できます。
2 つのソートされたリストをマージする (2 つの順序付けされたリンク リストを
マージ) - LeetCode 21 Merge k Sorted Lists (K 個の昇順リンク リストをマージ) - LeetCode 23
Top K Question: Top K の高頻度要素 - LeetCode 347
2.二分探索
**問題の説明:**順序付けされた (昇順を想定して) n 個の要素が与えられた場合、その中から特定の要素 x を見つけます。
**アルゴリズムのアイデア:** 順序付けされたシーケンスをほぼ同じサイズの 2 つの部分に分割し、中央の要素を特定の検索要素 x と比較します。x が中央の要素と等しい場合、検索は成功し、アルゴリズムは終了します。 x が中央の要素より小さい場合は、シーケンスの前半で検索を続けます。つまり、シーケンスの前半で分解とガバナンス操作を繰り返します。それ以外の場合は、シーケンスの後半で検索を続けます。つまり、シーケンスの後半で分解とガバナンス操作を繰り返します。
アルゴリズム設計:
(1) 検索間隔を設定します。
int left; // C++自动初始化为0
int right = n;
(2) 検索間隔[左、右]が存在しない場合は検索に失敗してリターンし、存在しない場合は(3)を実行します。
(3) 中央のビット mid = (left + right)/2 を取得し、x と a[mid] を比較します。状況は 3 つあります。
-
x < a[mid] の場合、right = mid - 1、検索は左半分の区間で実行され、(2) に進みます。
-
x > a[mid] の場合、left = mid + 1、検索は右半分の区間で実行され、(2) に進みます。
-
x = a[mid] の場合、検索は成功し、mid の値が返されます。
時間計算量の分析:
(1)顺序查找
- 最好时间复杂度:O(1)
- 最坏时间复杂度:O(n)
(2)二分查找
- 最好时间复杂度:O(1)
- 最坏时间复杂度:O(logn)
アルゴリズムの実装:
#include <iostream>
#include <vector>
int binarySearch(std::vector<int> nums, int l, int r, int x) {
if (l <= r) {
// 计算 mid 时需要防止溢出,left+(right-left)/2和(left+right)/2的结果相同,但是有效防止了left和right太大直接相加导致溢出
int mid = l + (r-l)/2;
if (nums[mid] == x) {
return mid;
} else if (nums[mid] > x) {
return binarySearch(nums, l, mid - 1, x);
} else {
return binarySearch(nums, mid + 1, r, x);
}
} else {
return -1;
}
}
int main() {
std::vector<int> nums{
2, 3, 4, 10, 40};
int x = 10;
int ans = binarySearch(nums, 0, nums.size() - 1, x);
if (ans == -1) {
std::cout << "未找到该数!" << std::endl;
} else {
std::cout << "该数的索引为:" << ans << std::endl;
}
return 0;
}