Algorithm divide and conquer strategy and application

In merge sorting, we use the divide-and-conquer strategy. In the divide-and-conquer strategy, we solve a problem recursively, applying the following three steps in each layer of recursion:

  • 分解: Divide the problem into some sub-problems, the form of the sub-problems is the same as the original problem, but on a smaller scale.
  • 解决: Solve the sub-problems recursively. If the scale of the sub-problem is small enough, stop the recursion and solve it directly.
  • 合并: Combine the solutions of the sub-problems into the solution of the original problem.

When the sub-problem is large enough to be solved recursively, it is called 递归情况. When the sub-problem becomes small enough that there is no need to recurse, the recursion has "bottomed" and entered 基本情况. Sometimes, in addition to smaller subproblems that are exactly the same as the original problem, it is also necessary to solve subproblems that are not exactly the same as the original problem. The solution of these sub-problems is considered as part of the merging step.

This time we will pass 最大子数组and 数组最大元素divide and conquer strategy to in-depth understanding of two cases

Appetizer: the largest element of the array

There are many 分治策略ways to solve the largest element in the array. Solving the problem from the perspective of thinking will give you a different pleasure.

  • Decomposition: Divide the array into two left and right sub-arrays by mid, and decompose recursively
  • Solution: When the array is indivisible, deal with基本情况
  • Combine: Compare the results returned by the sub-arrays and return the maximum value.

Sample code

    private static int maxValue(int[] array,int start,int end){
    
    
        if (start==end){
    
    //数组不可分时,返回即为最大值
            return array[start];
        }
        //计算中点
        int mid = (start+end)/2;
        //递归求解左右子数组最大值
        int l = maxValue(array,start,mid);
        int r = maxValue(array,mid+1,end);
        //返回处理结果
        return l>r?l:r;
    }

After the appetizer is served, let's order the main course to deepen your understanding?

Main course: the largest sub-array problem

最大子数组Refers to finding the continuous sub-array with the largest sum in an array containing negative numbers. (The entire array of non-negative numbers is the largest)

analysis

Suppose we are looking for the largest sub-array of A[low,high]. The divide-and-conquer strategy means that we have to divide the sub-array into two sub-arrays of the same size as possible. For example, find the middle position mid of the array, and then consider solving the two sub-arrays A[low,mid] and A[mid+1,high]. The position of any continuous sub-array A[i,j] of A[low,high] must be one of the following three situations:

  • 左边最大, Which is completely in A[low,mid], low ≤ i ≤ j ≤ mid
  • 右边最大, Which is completely located in A[mid+1,high], mid < i ≤ j ≤ high
  • 跨越中点,即low ≤ i ≤ mid < j ≤ high

The first two are sub-problems of the same form, but for the 跨越中点situation, we need special solutions

跨越中点

跨越中点For special cases, additional processing is required: starting with mid, calculate the accumulated and maximum element position to the left, calculate the accumulated maximum and element position to the right, and return the element position and the left and right accumulations. The sample code is as follows:

    /**
     * 计算跨越 mid 情况下的最大数组和
     *
     * @param array 待计算数组
     * @param start 起始位置
     * @param mid   中点位置
     * @param end   结束位置
     * @return int[最大子数组起始位置、最大子数组结束位置、最大子数组数值]
     */
    private static int[] maxCrossSum(int[] array, int start, int mid, int end) {
    
    
        int sum = 0;
        int leftSum = Integer.MIN_VALUE;
        int rightSum = Integer.MIN_VALUE;
        int leftPos = 0, rightPos = 0;
        //计算左侧累加最大值和位置
        for (int i = mid; i >= start; i--) {
    
    
            System.out.println("array ::: " + array[i]);
            sum = sum + array[i];
            if (sum > leftSum) {
    
    
                leftSum = sum;
                leftPos = i;
            }
        }

        System.out.println("start --- mid : max left sum is " + leftSum + "; max left position is " + leftPos);

        sum = 0;
        //计算右侧累加最大值和位置
        for (int i = mid + 1; i <= end; i++) {
    
    
            System.out.println("array ::: " + array[i]);
            sum = sum + array[i];
            if (sum > rightSum) {
    
    
                rightSum = sum;
                rightPos = i;
            }
        }

        System.out.println("mid --- end : max right sum is " + rightSum + "; max right position is " + rightPos);
        //返回最大和数组
        return new int[]{
    
    leftPos, rightPos, leftSum + rightSum};
    }

Global solution

After handling the special situation, we can 分治策略solve the problem accordingly .

  • Decomposition: Divide two sub-arrays in the middle of the array, recursively decompose the problem. Compare the situations on the left, right, and across the midpoint.
  • Solution: When the number of array elements is 1, enter 基本情况and solve the problem.
  • Combine: Combine the results of the sub-problems, determine the maximum value and return the result.

Sample code:

    /**
     * 对于分析中的1、2两种情况,可以通过递归拆分为相同子问题,因为都是在求指定上限(start 和 end 是确定的)的最大和子数组问题。
     * 第3种情况则特殊处理即可
     *
     * @param array 待计算数组
     * @param start 数组起始位置
     * @param end   数组结束位置
     * @return int[最大子数组起始位置、最大子数组结束位置、最大子数组数值]
     */
    private static int[] find(int[] array, int start, int end) {
    
    
        //如果数组中只有一个元素,直接返回当前元素
        if (end == start) {
    
    
            System.out.println("end == start" + start + " array value = " + array[start]);
            return new int[]{
    
    start, end, array[start]};
        }

        int mid = (start + end) / 2;
        //分别当前数组左侧最大值、右侧最大值、和包含 mid 最大值
        int[] left = find(array, start, mid);
        int[] right = find(array, mid + 1, end);
        int[] cross = maxCrossSum(array, start, mid, end);
        //比较最大值并返回
        if (left[2] > right[2] && left[2] > cross[2]) {
    
    
            return left;
        } else if (right[2] > left[2] && right[2] > cross[2]) {
    
    
            return right;
        } else {
    
    
            return cross;
        }
    }

I started writing when I came back from a business trip, and finally got here, hahaha, keep working hard! Next article "Heap Sorting of Sorting Algorithms"

Guess you like

Origin blog.csdn.net/lijie2664989/article/details/83514446