[Algorithm] Divide and conquer in four steps

The divide-and-conquer method has three steps in each level of recursion:
1) Decomposition: Decompose the original problem into several smaller, independent sub-problems with the same form as the original problem
2) Solve: if the sub-problem is smaller in scale Solve directly if it is easy to solve, otherwise solve each sub-problem recursively
3) Combine: Combine the solution of each sub-problem into the solution of the original problem.

Applicable scene

Technical information www.yehe.org

When the problem that applies to us is a big problem, and this big problem can be broken down into multiple small problems.

Divide and conquer four steps

  1. Clarify the decomposition strategy: clarify the decomposition strategy of the big problem step by step into the final small problem, and then we need to clarify the function of the function according to the decomposition strategy .
    For example, if our decomposition strategy is a half decomposition, then our function needs to have a range domain to determine the decomposition range; if it is a decreasing decomposition, then our function needs to have a count to record the result of the decreasing decomposition.

    For example, the big problem of quick sort can be decomposed into putting n elements to the correct position, and the big problem of the Tower of Hanoi is putting n discs to the correct position from bottom to top.

  2. Look for the smallest problem: the smallest problem is the most simplified version of the big problem, the starting state of the problem, and the smallest sub-problem is the exit.

  3. Solve minor problems: Use a decomposition strategy to decompose major problems into second minor ones. The second-smallest problem is the problem between the smallest problem and the big problem, which is slightly larger than the smallest problem. This makes the second-small problem universal to solve the big problem, that is, the general solution to the big problem can be found through the second-smallest problem. Get a solution from the next minor problem.

    For example, the second minor problem of quick sort is to place an element in the correct position, and the second minor problem of the Tower of Hanoi is to place a bottom disc in the correct position.

  4. Merging minor problems: This is added according to the needs of the problem.

1542615-20210119125206590-1139624038.png

Clear decomposition strategy

The first step is to clarify how to decompose the big problem step by step into the final small problem; and clarify what the function of this function is and what it wants to accomplish.
Decomposition strategy: big problem = n * small problem. If the big problem is an array, then the small problem is an element in the array.

For example, the big problem of the quick sort algorithm is to sort the n elements in the array and place them in the correct position, then the small problem of decomposition is to place an element in the array in the correct position.
The big problem of the Tower of Hanoi is to borrow the n plates on the A pillar and place the B pillar on the C pillar from large to small, then the small problem that decomposes is to borrow the bottom and largest plate on the A pillar to put B on the pillar. On the C pillar.

And this function is completely defined by you. In other words, we don't care what the code in the function is and how it is written, but we must first understand what your function is for.

For example: Finding the maximum value in an array
To solve this problem, the
first step is to clarify our decomposition strategy. Here, my decomposition strategy is half decomposition;
since the decomposition strategy is half decomposition, then we are about to write This function must specify the decomposition range, otherwise there is no way to split the decomposition.

Clear decomposition strategy: big problem = find the largest number from n elements, split into half, small problem = find the largest number from the comparison of two elements.

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

Find the smallest problem (initial conditions)

Divide and conquer is to continuously decompose big problems into sub-small problems in the internal code of function implementation, and then further decompose small problems into smaller problems. Therefore, we must find the end condition of divide and conquer, that is, given a threshold of decomposition, otherwise, it will continue to decompose itself, endlessly.

1542615-20210119112735821-2088674292.png

  • There must be a clear end condition. Because there is a divide and conquer "points" have "and" , it must have a clear point, to this point, do not "break down down" and start "Merge."

In the second step , we need to find out when the value of the parameter and the degree of decomposition, divide and conquer ends, and then directly return the result.
( Generally it is the initial condition, and then expand step by step from the initial condition to the final result )

Note: At this time, we must be able to directly know what the result of the function is based on the value of this parameter.

Let us continue to improve the maximum function above.
The second step is to find the minimum problem:
when l>=r, that is, there is only one element left, we can directly know that f(l) is the maximum value ;
then the recursive exit is that when l>=r, the function returns f(l ).
as follows:

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

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

Of course, when l>=r, we also know how much f(r) is equal to, and f(r) can also be used as a recursive exit. The divide-and-conquer exit may not be unique.

Solve minor problems

In the third step , we clarified the decomposition strategy before, and now is the time to use it. We need to use this decomposition strategy to decompose big problems into second-small ones. In this way, it can be decomposed to the smallest problem step by step, and then used as a function exit.

  • Minimal problem: decompose to only one element, l>=r, f(l) is the maximum
  • Decomposition strategy: half decomposition, f(nums, l, r) → f(nums, l, (l+r)/2), f(nums, (l+r)/2+1, r)

Divide and conquer:

  • Points: F(nums, l, r) → f(nums, l, (l+r)/2), f(nums, (l+r)/2+1, r). In this way, the problem is reduced from n to n/2 , and we only need to find the maximum value of these n/2 elements. In this way, slowly "point" from f(n), f(n/2) to f(1).
  • Union: In this way, you can " unify " step by step from 1, to 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);
}

Step 4: Solve the minor problem.
In the previous step, we decomposed the big problem into the next minor problem, then how to solve this minor problem? Solving this minor problem is also a solution to the problem for our next decomposition, so we can't be careless.
The way to solve the minor problem is to compare the size of the two minor problems and get the largest value, the problem can be solved.

// 明确分解策略:大问题=从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;
}

Merging minor issues

The merging here is to solve the second smallest problem, that is, to compare two elements to get the largest number.

At this point, the five steps of divide and conquer are completed, then the function of this divide and conquer function is also realized.
Maybe beginner readers will find it very strange, this can get the maximum value?
So, let's push it step by step.
Assuming that n is the number of elements in the array, f(n) is the maximum value of n elements,
f(1) has only one element, you can get a certain value
f(2) and compare the value of f(1), you can also Determine the value of
f(4) compared to f(2), and it can be determined
...
f(n/2)
f(n) can also be determined compared to f(n/2). You can
see if it can be resolved. Now, n can divide and conquer to get the result!

Instance

Maximum number

Find the largest number in an array.

Decomposition strategy: half and half

Find the largest element from l to 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;
}

Tower of Hanoi

The legend of the Tower of Hanoi

Tower of Hanoi: The problem of Tower of Hanoi (also known as Tower of Hanoi) is an educational toy derived from an ancient Indian legend. When Brahma created the world, he made three diamond pillars. On one pillar, 64 golden discs were stacked in order of size from bottom to top. The Brahma ordered the Brahmin to re-place the disc on another pillar in order of size from below. It is also stipulated that the disc cannot be enlarged on the small disc, and only one disc can be moved between the three pillars at a time.

If once every second, how long does it take? It takes more than 584.554 billion years to move these gold pieces, and the life expectancy of the solar system is said to be tens of billions of years. After 5845.54 billion years, all life on earth, including the Vatican Pagodas and temples, have long since disappeared.

Demo and analysis of the Tower of Hanoi game:

1) If there is a disk, A->C

If we have n>= 2, we can always regard it as two disks 1. The bottom disk 2. The upper disk
2) The top disk A->B
3) The bottom disk A ->C
4) Change all disks of Tower B from B->C

Code implementation of Tower of Hanoi:

Look at the teacher's code demo:

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);
        }
    }
}

Guess you like

Origin blog.csdn.net/weixin_48967543/article/details/115253836