题目要求如下:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为 O(n)。
例如输入的数组为 1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为 3, 10, -4, 7, 2,
因此输出为该子数组的和 18。
这个问题还是来自July微软面试100题序列,我的解题思路如下:
要求最大子数组之和,可以这样想:最大的子数组和可以有两部分构成:当前最大子数组和A、刚加入的一个元素b。先将这两部分加起来,作为临时的当前最大子数组和B,如果B>A,那么肯定要将b作为最大子数组的新元素,但是因为B = A + b,所以B>A完全可能只是因为b>A,而当前最大子数组和A也可能是一个负数,充当了减小即将获得的最大子数组和的角色,这时候当然要舍弃之前的最大子数组和序列,而从元素b开始收集最大子数组和序列;如果A为正的话,最大子数组只需扩张,把b加进来即可。如果B <=A,此时不能随便把b抛弃,因为后续的元素累加起来时,会使整个子数组的和增大,这时候的思想是把b加到b后面的元素上去,一起作为即将加入的一个元素,如此循环,就可以实现O(n)复杂度的最大子数组和求解。总之关键点在于(1)在B = A + b这个等式中A与b是处在同等重要的位置,(2)b可能是一个元素,也可能是某几个元素的和,用一种整体的思想看来待b。
#include "stdafx.h"
#include <iostream>
using namespace std;
//start、end记录了最大子数组在原数组中的区间
int GetMaxSubSequence(int* arrays,int n,int &start,int &end)
{
int curMaxSum = INT_MIN; //相当于A,最开始的时候初始化为最小整数
start = -1;
end = -1;
int tempTotal = 0; //相当于b
for (int i = 0; i < n; ++i)
{
tempTotal += arrays[i];
//total相当于B
int total = tempTotal + curMaxSum;
if(total > curMaxSum)
{
if(arrays[i] > total)
{
start = i;
end = i;
curMaxSum = arrays[i];
}
else
{
end = i;
curMaxSum += tempTotal;
}
tempTotal = 0;
}
}
return curMaxSum;
}
int _tmain(int argc, _TCHAR* argv[])
{
int arrays[] = {1, -2, 3, 10, -4, 7, 2, -5};
int start = 0,end = 0;
int maxVal = GetMaxSubSequence(arrays,8,start,end);
cout<<maxVal<<endl;
for (int i = start; i <= end;++i)
{
cout<<arrays[i]<<‘ ‘;
}
cout<<endl;
return 0;
}
程序运行截图:
July给出的答案里指出这是一个传统的的贪心问题,我不太懂贪心算法,以后肯定要探索的,这里想强调的是一种整体思想(对于b的处理),而实际编码结果与July的大同小异。
原文地址:http://blog.csdn.net/liao_jian/article/details/43603653