您的位置:首页 > 其它

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

2011-03-24 12:39 176 查看
[code]/*!


\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;


}

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: