[アルゴリズム] 4つのステップで分割統治

分割統治法には、再帰の各レベルで3つのステップがあります
。1)分解:元の問題を元の問題と同じ形式のいくつかの小さな独立したサブ問題に分解します
。2)解決:サブ問題が規模が小さい解決が容易な場合は直接解決し、そうでない場合は各サブ問題を再帰的に解決します
。3)結合:各サブ問題の解決策を元の問題解決策に結合します

該当シーン

技術情報www.yehe.org

私たちに当てはまる問題が大きな問題であり、この大きな問題を複数の小さな問題に分解できる場合。

4つのステップを分割統治する

  1. 分解戦略を明確にする:大きな問題の分解戦略を段階的に最終的な小さな問題に明確にし、次に分解戦略に従って関数の機能を明確にする必要があります。
    たとえば、分解戦略が半分の分解である場合、関数は分解範囲を決定するために範囲ドメインを持っている必要があります。それが減少する分解である場合、関数は減少する分解の結果を記録するためのカウントを持っている必要があります。

    たとえば、クイックソートの大きな問題は、n個の要素を正しい位置に配置することに分解できます。ハノイの塔の大きな問題は、n個のディスクを下から上に正しい位置に配置することです。

  2. 最小の問題を探します。最小の問題は、大きな問題の最も単純化されたバージョンであり、問​​題の開始状態であり、最小のサブ問題は終了です。

  3. マイナーな問題の解決:分解戦略を使用して、メジャーな問題を2番目のマイナーな問題に分解します。2番目に小さい問題は、最小の問題と大きな問題の間の問題であり、最小の問題よりもわずかに大きいため、2番目に小さい問題は、大きな問題を解決するために普遍的になります。つまり、大きな問題の一般的な解決策です。 2番目に小さい問題から見つけることができます。次の小さな問題から解決策を入手してください。

    たとえば、クイックソートの2番目の小さな問題は、要素を正しい位置に配置することであり、ハノイの塔の2番目の小さな問題は、下部ディスクを正しい位置に配置することです。

  4. マイナーな問題のマージ:これは、問題のニーズに応じて追加されます。

1542615-20210119125206590-1139624038.png

明確な分解戦略

最初のステップは、大きな問題を段階的に最終的な小さな問題に分解する方法を明確にすることです。そして、この関数の機能とは何か、そしてそれが何を達成したいのかを明確にします。
分解戦略:大きな問題= n *小さな問題。大きな問題が配列である場合、小さな問題は配列内の要素です。

たとえば、クイックソートアルゴリズムの大きな問題は、配列内のn個の要素を並べ替えて正しい位置に配置することです。次に、分解の小さな問題は、配列内の要素を正しい位置に配置することです。
ハノイの塔の大きな問題は、Aピラーのnプレートを借りて、CピラーのBピラーを大きいものから小さいものへと配置することです。次に、分解される小さな問題は、Aの一番下の最大のプレートを借りることです。 BをCピラーに乗せるピラー。

そして、この関数は完全にあなたによって定義されます。つまり、関数内のコードが何であるか、どのように記述されているかは関係ありませんが、最初に関数の目的を理解する必要があります。

例:配列の最大値を見つける
この問題を解決するための
最初のステップは、分解戦略を明確にすることです。ここでは、分解戦略は半分分解です。分解戦略は半分分解な
ので、この関数を記述します。分解範囲を指定する必要があります。指定しないと、分解を分割する方法がありません。

明確な分解戦略:大きな問題= n個の要素から最大数を見つけ、半分に分割し、小さな問題= 2つの要素の比較から最大数を見つけます。

//找出一个数组中的最大值
// 明确分解策略:大问题=从n个元素中找到最大的数字并返回,折半分解,小问题=从2个元素比较大小找到最大数字并返回。
int f(int[] nums, int l, int r) {
    
}

最小の問題を見つける(初期条件)

分割統治法は、関数実装の内部コードで大きな問題をサブ小さな問題に継続的に分解し、さらに小さな問題を小さな問題にさらに分解することです。したがって、分割統治の終了条件を見つける必要があります。つまり、分解のしきい値が与えられている場合、それ以外の場合は、無限に分解し続けます。

1542615-20210119112735821-2088674292.png

  • 明確な終了条件が必要です。分割統治法の「ポイント」に「and」があるので、明確なポイントが必要です。この時点までは、「分解」して「マージ」を開始しないでください。

2番目のステップでは、パラメーターの値と分解の程度、分割統治がいつ終了するかを調べて、結果を直接返す必要があります。
通常は初期条件であり、初期条件から最終結果まで段階的に展開します

注:現時点では、このパラメーターの値に基づいて、関数の結果が何であるかを直接知ることができなければなりません。

上記の最大機能を改善し続けましょう。
2番目のステップは、最小の問題を見つけることです
。l> = rの場合、つまり要素が1つしか残っていない場合、f(l)が最大値であることが直接わかります
その後、再帰的終了はl> =の場合です。rの場合、関数はf(l)を返します。
次のように:

// 明确分解策略:大问题=从n个元素中找到最大的数字并返回,折半分解,小问题=从2个元素比较大小找到最大数字并返回。
int f(int[] nums, int l, int r) {

      // 寻找最小问题:最小问题即是只有一个元素的时候
      if (l >= r) {
            return nums[l];
      }
}

もちろん、l> = rの場合、f(r)がどれだけ等しいかがわかります。f(r)は再帰的な出口としても使用できます。分割統治法の出口は一意ではない場合があります。

小さな問題を解決する

3番目のステップでは、前に分解戦略を明確にしましたが、今がそれを使用するときです。この分解戦略を使用して、大きな問題を2番目に小さな問題に分解する必要があります。このようにして、それを段階的に最小の問題に分解し、関数出口として使用することができます。

  • 最小の問題: 1つの要素のみに分解、l> = r、f(l)が最大
  • 分解戦略:半分解、f(nums、l、r)→f(nums、l、(l + r)/ 2)、f(nums、(l + r)/ 2 + 1、r)

分割統治:

  • ポイント: F(nums、l、r)→f(nums、l、(l + r)/ 2)、f(nums、(l + r)/ 2 + 1、r)。このようにして、問題はnからn / 2減少し、これらのn / 2要素の最大値を見つけるだけで済みます。このようにして、f(n)、f(n / 2)からf(1)にゆっくりと「ポイント」ます。
  • ユニオン:このようにして、1からn / 2、n ...まで段階的に統合できます。
// 明确分解策略:大问题=从n个元素中找到最大的数字并返回,折半分解,小问题=从2个元素比较大小找到最大数字并返回。
int f(int[] nums, int l, int r) {

      // 寻找最小问题:最小问题即是只有一个元素的时候
      if (l >= r) {
            return nums[l];
      }

      // 使用分解策略
      int lMax = f(nums, l, (l+r)/2);
      int rMax = f(nums, (l+r)/2+1, r);
}

ステップ4:小さな問題を解決します。
前のステップでは、大きな問題を次の小さな問題に分解し、次にこの小さな問題を解決する方法を教えてください。この小さな問題を解決することは、次の分解の問題の解決策でもあるので、不注意ではありません。
マイナーな問題を解決する方法は、2つのマイナーな問題のサイズを比較し、最大の値を取得することです。問題を解決できます。

// 明确分解策略:大问题=从n个元素中找到最大的数字并返回,折半分解,小问题=从2个元素比较大小找到最大数字并返回。
int f(int[] nums, int l, int r) {

      // 寻找最小问题:最小问题即是只有一个元素的时候
      if (l >= r) {
            return nums[l];
      }

      // 使用分解策略
      int lMax = f(nums, l, (l+r)/2);
      int rMax = f(nums, (l+r)/2+1, r);

      // 解决次小问题:比较两个元素得到最大的数字
      return lMax > rMax ? lMax : rMax;
}

マイナーな問題のマージ

ここでのマージは、2番目に小さい問題を解決することです。つまり、2つの要素を比較して、最大の数を取得します。

この時点で、分割統治の5つのステップが完了し、この分割統治機能の機能も実現されます。
たぶん初心者の読者はそれが非常に奇妙だと思うでしょう、これは最大の価値を得ることができますか?
それでは、段階的にプッシュしていきましょう。
nが配列内の要素の数であり、f(n)がn要素の最大値であり、
f(1)が1つの要素しかない場合、特定の値
f(2)を取得し、f(の値を比較できます。1)、
f(2)と比較してf(4)の値を決定することもでき、それを決定することができます
...
f(n / 2)
f(n)はf(n / 2と比較して決定することもできます)それが
解決できるかどうか確認できます。これで、nは分割統治して、結果を得ることができます

インスタンス

最大数

配列内の最大数を見つけます。

分解戦略:半分と半分

lからrまでの最大の要素を見つけます。

// 明确分解策略:大问题=从n个元素中找到最大的数字并返回,折半分解,小问题=从2个元素比较大小找到最大数字并返回。
int f(int[] nums, int l, int r) {

      // 寻找最小问题:最小问题即是只有一个元素的时候
      if (l >= r) {
            return nums[l];
      }

      // 使用分解策略
      int lMax = f(nums, l, (l+r)/2);
      int rMax = f(nums, (l+r)/2+1, r);

      // 解决次小问题:比较两个元素得到最大的数字
      return lMax > rMax ? lMax : rMax;
}

ハノイの塔

ハノイの塔の伝説

ハノイの塔:ハノイの塔(ハノイの塔としても知られています)の問題は、古代インドの伝説に由来する教育玩具です。ブラフマーが世界を創造したとき、彼は3つのダイヤモンドの柱を作りました.1つの柱に、64個の金色の円盤が下から上にサイズ順に積み重ねられました。ブラフマーは、バラモンに、下からサイズの順にディスクを別の柱に再配置するように命じました。また、小さなディスクではディスクを拡大することはできず、一度に3つの柱の間で移動できるディスクは1つだけであると規定されています。

1秒に1回の場合、どのくらい時間がかかりますか?これらの金貨を動かすのに5,845億5,400万年以上かかり、太陽系の平均余命は数百億年と言われています。58455.4億年後、バチカンの塔や寺院を含む地球上のすべての生命は、長い間姿を消しました。

ハノイの塔ゲームのデモと分析:

1)ディスクがある場合、A-> C

n> = 2の場合、常に2つのディスクと見なすことができます1.下部のディスク2.上部のディスク
2)上部のディスクA-> B
3)下部のディスクA-> C
4)のすべてのディスクを変更しますB-> CからのタワーB

ハノイの塔のコード実装:

先生のコードデモを見てください:

package com.atguigu.dac;

public class Hanoitower {

    public static void main(String[] args) {
        hanoiTower(10, 'A', 'B', 'C');
    }
    
    //汉诺塔的移动的方法
    //使用分治算法
    // 明确分解策略:我们的问题是有n个盘子,可是如果是n个盘子的话我们不会分,不知道结果;如果盘子数量为1、2、3就好了,所以我们按盘子数依次减一分解
    public static void hanoiTower(int num, char a, char b, char c) {
        // 寻找最小问题:只有一个盘
        //如果只有一个盘
        if(num == 1) {
            System.out.println("第1个盘从 " + a + "->" + c);
        } else {
            // 解决次小问题:由于我们是按盘子数-1来进行分解的,所以次小问题是一个盘子和n-1个盘子的汉诺塔,将一个最下面的盘子摆放到正确的位置
            //如果我们有 n >= 2 情况,我们总是可以看做是两个盘 1.最下边的一个盘 2. 上面的所有盘
            //1. 先把 最上面的所有盘 A->B, 移动过程会使用到 c
            hanoiTower(num - 1, a, c, b);
            //2. 把最下边的盘 A->C
            System.out.println("第" + num + "个盘从 " + a + "->" + c);
            //3. 把B塔的所有盘 从 B->C , 移动过程使用到 a塔  
            hanoiTower(num - 1, b, a, c);
        }
    }
}

おすすめ

転載: blog.csdn.net/weixin_48967543/article/details/115253836