Recursion and partition / Dynamic Programming | 6: the biggest problem subarray

Problem: Find the array A [l..r] each element in the sum of the maximum continuous non-empty array. We call such an array called the largest sub-array.

This article presents three solutions: to solve the violence, divide and conquer, dynamic programming. Time complexity in descending order. 


In order to facilitate spread function results, we define a structure to store the maximum subarray elements, i.e. the sub-array subscript and bounds of the original array and the corresponding.

typedef struct subArray {
    int l;  //子数组的左边界
    int r;  //子数组的右边界
    int sum;  //子数组每一项的和
} SUB_ARRAY;

Method One: Solution of violence - O (n ^ 2) 

Obviously, you need two for loop to loop through all of the sub-array of the original array, time complexity is very high.

This bad idea, not the code.


Method Two: Divide and Conquer - O (nlgn)

1, points (Divide)

We are looking for an array a [l, r] is the maximum sub-arrays, the array we can be decomposed into two sub-arrays of equal size as possible . Found i.e. mid center position of the array, then divided into a left sub-array a [l, mid] and the right sub-array a [mid + 1, r] be considered.

2, treatment (Conquer)

Then a [l, r] of the present embodiment has three sub-arrays, sub-arrays in the left, in the right sub-arrays, the mid-point across the array. We should look at the three biggest range of sub-arrays, both front we can recursively called to solve , because the problem is still seeking two sub-sub-arrays largest general question, but smaller scale. Then find the maximum span midpoint sub-arrays, we can write a single function, in O (n) time, to both sides from the mid traverse can.

The complete code is as follows:

// Created by A on 2020/3/5.

#include <climits>
typedef struct subArray {
    int l;  //子数组的左边界
    int r;  //子数组的右边界
    int sum;  //子数组每一项的和
} SUB_ARRAY;

/* 在数组a[l,r]内找到包含m下标位置的最大子数组 */
SUB_ARRAY FindMaxCrossingSubarray(int a[], int l, int m, int r) {
    /* 计算从m出发的左半边数组的最大子数组 */
    int leftMax = INT_MIN, leftIndex, t = 0;
    for (int i = m; i >= l; i--) {
        t += a[i];
        if (t > leftMax) {
            leftIndex = i;  //最大位置对应的下标
            leftMax = t;  //最大和
        }
    }
    t = 0;
    /* 计算从m + 1出发的右半边数组的最大子数组 */
    int rightMax = INT_MIN, rightIndex;
    for (int i = m + 1; i <= r; i++) {
        t += a[i];
        if (t > rightMax) {
            rightIndex = i;  //最大位置对应的下标
            rightMax = t;  //最大和
        }
    }
    SUB_ARRAY ans;
    ans.l = leftIndex;
    ans.r = rightIndex;
    ans.sum = leftMax + rightMax;
    return ans;
}
/* 在数组a[l,r]内找到最大子数组(非空!) */
SUB_ARRAY FindMaxSubarray(int a[], int l, int r) {
    /* 递归的终点,数组只有一个元素 */
    if(l == r) {
        SUB_ARRAY ans;
        ans.l = ans.r = l;
        ans.sum = a[l];
        return ans;  //直接将原数组作为最大子数组返回
    }
    int mid = (l + r) / 2;  //中间位置
    SUB_ARRAY leftAns = FindMaxSubarray(a, l, mid); //递归地求mid左侧的最大子数组
    SUB_ARRAY rightAns = FindMaxSubarray(a, mid + 1, r);  //递归地求mid右侧地最大子数组
    SUB_ARRAY midAns = FindMaxCrossingSubarray(a, l, mid, r);  //求包含mid地最大子数组
    /* 返回三者中和最大的 */
    if(leftAns.sum > midAns.sum && leftAns.sum > rightAns.sum)
        return leftAns;
    else if(midAns.sum > rightAns.sum)
        return midAns;
    else
        return rightAns;
}

Method three: Dynamic Programming - O (n) 

1, the algorithm description 

This is a great non-recursive method of linear time complexity:

If the maximum subarray known array a [0..j], then a [0..j + 1] is the largest sub-array is one of the following two situations:

  1. Subarray is the maximum array a [0..j]: Not including the first item j + 1
  2. J + 1 includes a first item: a [k..j + 1] (where 0 <= k <= j + 1)

2, algorithm

Scratch loop through the array a, traverse to the index subscript i: a cur recording a [0..i] within comprises i-th item largest sub-arrays, with the maximum recording sub ans a [0..i] in array. (Explained below when using cur (), ANS () represent two variables in brackets traversed subscript index represented in the traverse to a position corresponding to the cur ans.)

If known cur (i) and ans (i), then continue to traverse the next element:

  1. According to the definition of cur, cur (I +. 1) should be cur (i) + a [i + 1] and a [i 1 +] larger values
  2. The algorithm described in said: ANS (I +. 1) should be a larger value cur (i + 1) and ans (i) in . Then traverse completed ans is the answer.

The following is a specific algorithm for drawing a traverse:

 

Understand the algorithm, the code is very simple:

#include <climits>
typedef struct subArray {
    int l;  //子数组的左边界
    int r;  //子数组的右边界
    int sum;  //子数组每一项的和
} SUB_ARRAY;


/* 在数组a[l,r]内找到最大子数组(非空!) */
SUB_ARRAY FindMaxSubarray1(int a[], int l, int r) {
    int ans = INT_MIN, cur = INT_MIN;
    int curLeft, leftIndex, rightIndex;  //记录cur对应的子数组左下标、记录ans对应的子数组左右下标
    for (int i = l; i <= r; i++) {
        /* 找到a[ 0..i ]内包含第i项的最大子数组 */
        if (cur + a[i] >= a[i])
            cur += a[i];
        else {
            cur = a[i];
            curLeft = i;
        }
        /* 更新a[ 0..i ]内的最大子数组 */
        if (cur > ans) {
            ans = cur;
            leftIndex = curLeft;
            rightIndex = i;
        }
    }
    /* 返回答案 */
    SUB_ARRAY result;
    result.l = leftIndex;
    result.r = rightIndex;
    result.sum = ans;
    return result;
}


end 

No personal welcome attention to the public " chicken wings Programming" , here is a serious and well-behaved code agricultural one.

---- do the most well-behaved blog er, do the most solid programmer ----

Aims to carefully write each article, usually aggregated into notes will push updates -

Here Insert Picture Description

Published 138 original articles · won praise 63 · views 10000 +

Guess you like

Origin blog.csdn.net/weixin_43787043/article/details/104696020