Coding算法导论

本系列文章主要针对算法导论一书上的算法,将书中的伪代码用C++实现

代码未经过大量数据测试,如有问题,希望能在回复中指出!

(一)问题描述

给定一个数组,求数组中连续的子数组的和,找出和的最大值。如

数组A:-1,-4,4,3,2,-3

应该返回最大值9。

(二)问题求解

本题想到了两个思路:暴力求解法和分治法。前者就不多说了,本文主要讨论分治法。

分治法的大致思路:对于A[low,high]这个数组,任何的连续子数组A[i,j]的位置必然是一下三种情况之一:

  • 完全位于子数组A[low,mid]中,因此有
  • 完全位于子数组A[mid+1,high]中,因此
  • 跨越了中点,因此

对于前两种情况,只需要找出左右和右边的最大子数组即可。

对于第三种情况,我们只需要找到A[i,mid]和A[mid+1,j]的最大子数组,然后相加即可。

好了,问题思考到这里就差不多了。下面来看具体的C++实现代码。

#include <iostream>
using namespace std;
/*
求解最大子数组
*/
int find_max_cross_subarray(int A[], int low, int mid, int high)
{
    int sum = 0;
    int left_sum = 0, right_sum = 0;
    for (int i = mid; i >= low; i--)//求A[i,mid]的最大子数组
    {
        sum += A[i];
        left_sum = left_sum > sum ? left_sum : sum;
    }
    sum = 0;
    for (int j = mid + 1; j <= high;j++)//求A[mid,j]的最大子数组
    {
        sum += A[j];
        right_sum= right_sum > sum ? right_sum : sum;
    }
    return left_sum + right_sum;//两个相加作为返回值
}
int find_max_cross_subarray(int A[] , int low ,int high)
{
    if (low == high)//递归退出
    {
        return A[low];
    }
    int mid = (low + high) / 2;
    int left = find_max_cross_subarray(A, low, mid);//求左边最大子数组
    int right = find_max_cross_subarray(A, mid + 1, high);//求右边最大子数组
    int cross = find_max_cross_subarray(A, low, mid, high);//求跨越了中点的最大子数组
    if (left >= right&&left >= cross) return left;//返回三者中的最大值
    else if (right >= left && right >= cross) return right;
    else return cross;
}
int main()
{
    //测试用例
    int A[16] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
    int ret = find_max_cross_subarray(A, 0, 15);
    cout << ret << endl;
    return 0;
}