题目:现在有一个整型的数组,能帮我求出该数组中连续最大和吗?请用最优的算法来实现。
很多年前看到过这道题,说实话,第一次看到这道题的时候心里有很多疑问。
1. 什么叫连续?
2. 相加为什么还有最大一说?
3. 最优的算法?说明有暴力解法,也有优化的解法
给自己找个例子,看什么样的例子能够回答我们的前两个问题。大家停顿一下,等会再往后读。
数组 | 最大连续和 | 注意 |
1, 2, -2, 1, -2, -7, 16 | 16 | 前面累加的如果是负数就舍弃 |
1, 2, -2, 1, -2, -7, 16, -1 | 16 | 最后一个-1不要再加了 |
1, 7, -7, 16, -1 | 17 | 前面累加为正数就保留 |
-1, -7, -7, -16, -1 | -1 | 全是负数,保留最大的元素值 |
这也算是测试驱动开发的过程。我们从例子中会发现,
1. 连续是指1+2-2+1这样的过程,
2. 而最大是指,1+2-2+1-2-7 < 0, 我们就不要了。
3. 从第二个例子中我们发现最后一个元素是-1,我们不能往后加了,或者说加了之后比之前相加的要小,我们取之前的值。
4. 最后例子算是一个特例,整个数组都是负的,那我们的结果应该是负数中最大的那一个。
所以,我们的算法里需要考虑到:
1. 找最大值
2. 保留最大和,和哨兵保存当前的和,之后再比较
接下来我们就一起看代码了啊(大家可以试一下,不用第一次就考虑到所有的情况,持续优化):
/// <summary>
/// 1, 2, -2, 1,-2, -7, 16
/// </summary>
/// <param name="input">输入数组</param>
/// <returns>最大连续和</returns>
public static int MaxSum(int[] input)
{
if (input == null || input.Length == 0) return 0;
// 作哨兵,保存当前的和
int tempSum = 0;
// 保存最大的,会和哨兵比,哨兵大的话我们就更新过来
// 注意这里的默认值,取最小的int值,是为了处理全是负的情况
int sum = int.MinValue;
// 找数组中最大的数
int maxElement = int.MinValue;
for (int index = 0; index < input.Length; index++)
{
// 正好省下一个for循环,顺便找出最大的值
if (input[index] > maxElement)
{
maxElement = input[index];
}
// 算当前的和
tempSum += input[index];
// 当前的和如何已经是负数了,则说明它对之后的和肯定没有贡献,我们舍弃掉
if (tempSum < 0)
{
tempSum = 0;
}
// 如果当前的tempsum是正的,并且比之前的sum小,我们就保留tempsum
// 当 tempsum < 0 的时候,可能说明数组里都是负数,我们暂时不保留,最后再处理
else if (tempSum > sum)
{
sum = tempSum;
}
}
// 最后看下,到底谁最大
return sum > maxElement ? sum : maxElement;
}
我们一块看下测试和结果:
大家如果对以上算法有什么疑问,欢迎交流哈。有更优的解法也欢迎讨论。有兴趣的同学可以关注我的公众号,好了,欢迎大家关注我的公众号,还有我的系列视频教程, 数据结构与算法 和 微软经典算法面试题辅导。大家有什么更好的解法,也欢迎讨论哈。