练习系列 - 5、求子数组的最大和

/*!
\author LiuBao
\date 2011/3/24
\brief 求子数组的最大和
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如:输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。
思路:对长度为N的数组a从左到右扫描求和,抛弃小于0的子数组和,记函数为Sum(i)。
1、Sum(0) = a[0]
2、Sum(i) = Sum(i - 1) > 0 ? Sum(i - 1) + a[i] : a[i], (0 < i <= N - 1)
Sum(i)(0 <= i <= N - 1)中最大的,Max(Sum(i)),即为最大子数组和。
*/
#include <stdio.h>
#include <stdlib.h>
 
/*!
经典递归算法,直接使用状态转移,最大值保存在*sum中
\param array 数组
\param i 递归下标i
\param sum 最大值变量指针
\return Sum(i)
*/
int max_sum_old(const int *array, int i, int *sum)
{
    if(i)
    {
        int last_sum = max_sum_old(array, i - 1, sum);          //last_sum = Sum(i - 1)
 
        if(last_sum > *sum) *sum = last_sum;                    //更新*sum使之始终等于max(Sum(i))
 
        return last_sum > 0 ? last_sum + array[i] : array[i];   //Sum(i) = Sum(i - 1) > 0 ? Sum(i - 1) + a[i] : a[i]
    }
    else
        return array[0];                                        //Sum(0) = a[0]
}
 
/*!
在线算法,遍历过程能够直接计算出所需的状态值,返回最大子序列和
\param array 数组
\param n 数组元素个数
\return 数组中最大子序列和
*/
int max_sum(const int *array, int n)
{
    int i;                                                      ///< 遍历下标
    int sum = array[0];                                         ///< 最大子序列和
    int current = 0;                                            ///< 当前子序列和
    int new_start = -1;                                         ///< 新子序列开始位置
    int start = -1, end = -1;                                   ///< 最大子序列开始、结束位置
 
    for(i = 0; i < n; ++i)
    {
        if(current > 0)                                         // 当前子序列和 > 0
            current += array[i];                                // 向后扩展子序列,使之包含a[i]
        else                                                    // 当前子序列和 <= 0
        {
            current = array[i];                                 // 抛弃前一个子序列,重新计算当前子序列
            new_start = i;                                      // 记录新子序列的开始位置
        }
 
        if(current > sum)                                       // 若当前子序列和 > 最大子序列和
        {
            sum = current;                                      // 最大子序列和更新为当前子序列和
            start = new_start;                                  // 保存当前子序列的开始位置
            end = i;                                            // 保存当前子序列的结束位置
        }
    }
 
    printf("start: %d, end: %d\n", start, end);                 // 打印最大子序列开始、结束位置
 
    return sum;
}
 
int main()
{
    int dataSet[] = {1, -2, 3, 10, -4, 7, 2, -19, 3, 6};        ///< 测试数据集合
 
    /* 使用递归算法输出最大子序列和 */
    int sum = 0;
    max_sum_old(dataSet, sizeof(dataSet) / sizeof(int), &sum);
    printf("Max Sum: %d\n", sum);
 
    /* 使用在线算法输出最大子序列和 */
    printf("Max Sum: %d\n", max_sum(dataSet, sizeof(dataSet) / sizeof(int)));
 
    return 0;
}
posted @ 2011-03-24 12:39  紫红的泪  阅读(572)  评论(0编辑  收藏  举报