最大子数列问题的目标是在数列的一维方向找到一个连续的子数列,使该子数列的和最大。例如,对一个数列[-2, 1, -3, 4, -1, 2, 1, -5, 4],其中连续子数列中和最大的是[4, -1, 2, 1],其和为6。该问题最初是由Ulf Grenander教授在1977年提出的,直到1984年才由Jay Kadane提出了该问题的线性算法,该算法虽然长度很短,但其实并不容易理解。
Kadane算法
在正式介绍算法之前让我们来分析一下这个问题。我们先将问题进行拆分,指定数组中某个元素nums[i](假设求值最大子数列问题的数组为nums)作为最大子数列的末尾元素时,能找到的最大子数列的值是多少?我们会发现nums[i]作为末尾元素时,最大子数列问题的值必然是num[i]本身或者是nums[i-1]作为末尾元素时能找到的最大子数列再拼接上nums[i](当以nums[i-1]作为末尾元素时能找到的最大子数列问题的值为负数时,此时以nums[i]作为末尾元素的最大子数列问题的值就是nums[i]本身)。那么我们是不是只需要从头到尾遍历一遍数组,依次计算出每个位置的元素nums[i]作为末尾元素时能找到的最大子数列问题的值,即可找到全局的最大子数列的值。
我们来看看代码:
public int maxSubArray(int[] nums) {
int maxEndingHere = nums[0];
int maxSoFar = nums[0];
for (int i = 1; i < nums.length; i++) {
int num = nums[i];
maxEndingHere = Math.max(num, maxEndingHere + num);
maxSoFar = Math.max(maxEndingHere, maxSoFar);
}
return maxSoFar;
}
代码中,maxEndingHere表示以元素nums[i]结尾时最大子数列问题的值,maxSoFar表示遍历到nums[i]时,求得的全局最大子数列问题的值。