求解最大子数组问题

来源:互联网 发布:没钱能拍网络剧吗 编辑:程序博客网 时间:2024/05/30 13:41

明日复明日,明日何其多。我生待明日,万事成蹉跎。


求解最大子数组的问题一般会有类似这样的描述:给定一个数组,求出数组中一个连续的子数组,该子数组中元素的和为所有连续子数组中的最大值。

这样的问题是典型分治思想,适合使用递归处理。我们可以考虑将给定的数组分成两部分,那么最大子数组必定存在于左侧部分,或者右侧部分,或者是跨越了分界线的部分。那么,只要分别求出这三种情况下的最大子数组,再进行比较,就能得出最后的结果。从这里的分析可以看出,我们采用了分解数组(分治思想),继而对每次的分解结果进行同样的处理(递归),最后求解(合并)。


C++实现示例:

int main(){    int A[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};    int low = 0;    int high = 0;    int sum = 0;    find_max_subarray(A, 0, 15, low, high, sum);    cout << "{";    for (int i = low; i <= high; i++)    {        cout << A[i] << ", ";    }    cout << "(sum = " << sum << ")" << "}" << endl;    system("pause");    return 0;}void find_max_subarray(int* arr, int low, int high,                        int& result_low, int& result_high, int& result_sum){    if (low == high)    {        result_low = low;        result_high = high;        result_sum = arr[low];        return;    }    int mid = (low + high) / 2;    int left_low = 0;    int left_high = 0;    int left_sum = 0;    find_max_subarray(arr, low, mid, left_low, left_high, left_sum);    int right_low = 0;    int right_high = 0;    int right_sum = 0;    find_max_subarray(arr, mid + 1, high, right_low, right_high, right_sum);    int cross_low = 0;    int cross_high = 0;    int cross_sum = 0;    find_max_crossing_subarray(arr, low, mid, high, cross_low, cross_high, cross_sum);    if (left_sum >= right_sum && left_sum >= cross_sum)    {        result_low = left_low;        result_high = left_high;        result_sum = left_sum;    }    else if (right_sum >= left_sum && right_sum >= cross_sum)    {        result_low = right_low;        result_high = right_high;        result_sum = right_sum;    }    else    {        result_low = cross_low;        result_high = cross_high;        result_sum = cross_sum;    }}void find_max_crossing_subarray(int* arr, int low, int mid, int high,                                 int& cross_low, int& cross_high, int& cross_sum){    int sum = 0;    int left_sum = arr[mid] - 1;    for (int i = mid; i >= low; i--)    {        sum += arr[i];        if (sum >= left_sum)        {            left_sum = sum;            cross_low = i;        }    }    sum = 0;    int right_sum = arr[mid + 1] - 1;    for (int i = mid + 1; i <= high; i++)    {        sum += arr[i];        if (sum >= right_sum)        {            right_sum = sum;            cross_high = i;        }    }    cross_sum = left_sum + right_sum;}

Java实现示例:
public static void main(String[] args) {    int A[] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 };    int[] result = new int[3];    findMaxSubarray(A, 0, 15, result);    // output    for (int i = result[0]; i <= result[1]; i++) {        System.out.print(A[i]);        System.out.print(", ");    }    System.out.println("Sum = " + result[2]);}public static void findMaxSubarray(int[] arr, int low, int high, int[] result) {    if (low == high) {        result[0] = low; // the left index of the array        result[1] = high; // the right index of the array        result[2] = arr[low]; // the sum result of the sub-array        return;    }    int mid = (low + high) / 2;    // index 0 - low index of the sub-array    // index 1 - high index of the sub-array    // index 2 - sum of the sub-array    int[] leftResult = new int[3];    findMaxSubarray(arr, low, mid, leftResult);    int[] rightResult = new int[3];    findMaxSubarray(arr, mid + 1, high, rightResult);    int[] crossResult = new int[3];    findMaxCrossingSubarray(arr, low, mid, high, crossResult);    if (leftResult[2] >= rightResult[2] && leftResult[2] >= crossResult[2]) {        System.arraycopy(leftResult, 0, result, 0, 3);    }    else if (rightResult[2] >= leftResult[2] && rightResult[2] >= crossResult[2]) {        System.arraycopy(rightResult, 0, result, 0, 3);    }    else {        System.arraycopy(crossResult, 0, result, 0, 3);    }}public static void findMaxCrossingSubarray(int[] arr, int low, int mid, int high, int[] result) {    int sum = 0;    int left_sum = arr[mid] - 1;    for (int i = mid; i >= low; i--) {        sum += arr[i];        if (sum > left_sum) {            left_sum = sum;            result[0] = i; // low index of the sub-array        }    }    sum = 0;    int right_sum = arr[mid + 1] - 1;    for (int i = mid + 1; i <= high; i++) {        sum += arr[i];        if (sum > right_sum) {            right_sum = sum;            result[1] = i; // high index of the sub-array        }    }    result[2] = left_sum + right_sum;}



0 0