题目:一个整数数组中的元素有正有负,在该数组中找出一个连续的数组,要求连续的数组的和是最大的,我们成这个子数组就是最大的连续子数组。
分析:对于这个找最大子数组的数组,如果这个数组里面全部是正数,那就不用考虑了,所有元素相加就是最大的子数组了;如果全部为负,则就是找里面的最大的元素;如果有正有负,则情况会麻烦一下。下面提供四种解法。
解法一:
int FindSubSum1(int *arr,int length)
{
int maxSum = 0;
for(int i = 0; i < length; i++)
{
int curMax = 0;
for(int j = i; j < length; j++)
{
curSum += arr[i];
if(curSum > maxSum)
maxSum = curSum;
}
}
return maxSum;
}
解法看起来就非常的简单粗暴,两轮循环,先从第一个数开始往后累加,每次累加之后都和最大的和比较,找到最大的那个累加和;然后从第二个往后累加,以此类推。该算法的时间复杂度为O(n^2)。
解法二:
int FindSubSum2(int *arr,int length)
{
int maxSum = 0, curMax = 0;
for(int i = 0; i < length; i++)
{
curSum += arr[i];
if(curSum > maxSum)
maxSum = curSum;
if(curSum < 0)
curSum = 0;
}
}
return maxSum;
}
该解法采用一种特别的方式,只遍历数组一遍,当然,这种方法要求数组中必须要有非负数存在。我遍历的时候遇到和小于0的,肯定就不是最大的那个数组了,这个非常容易想明白。
解法三:
int max(int a,int b,int c)
{
int max = (b > a) ? b : a;
max = (max > c) ? max :c;
return max;
}
int FindSubMax3(int *arr,int left,int right)
{
int maxLeftSum,maxRightSum; //左右的最大的和
int maxLeftBorderSum,maxRightBorderSum; //含中间边界的左右部分最大和
int leftBorderSum,rightBorderSum; //含中间边界的左右部分当前和
if(left == right)
return arr[left];
//求含中间边界的左右部分的最大值
int center = (left + right) / 2;
maxLeftBorderSum = 0;
leftBorderSum = 0;
for(int i = center; i >= left; i--)
{
leftBorderSum += arr[i];
if(leftBorderSum > maxLeftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
maxRightBorderSum = 0;
rightBorderSum = 0;
for(int i = center + 1; i <= right; i++)
{
rightBorderSum += arr[i];
if(rightBorderSum > maxRightBorderSum)
maxRightBorderSum = rightBorderSum;
}
//递归求左右部分的最大值
maxLeftSum = FindSubMax3(arr, left, center);
maxRightSum = FindSubMax3(arr, center + 1, right);
return max(maxLeftSum,maxRightSum,maxLeftBorderSum + maxLeftBorderSum);
}
这种解法就是求解分为三部分,以位于中间的那个值为界,分别对其左边、右边、跨过中间值这三部分求值,然后比较它们的大小,其中左边和右边的比较好理解,跨过中间的就需要两部分来拼接了,也就是最后的maxLeftBorderSum + maxLeftBorderSum。这个的时间复杂度为O(nlogn)。
解法四:
int FindSubMax4(int *arr,int length)
{
int dp[length];
dp[0] = arr[0];
int maxSum = dp[0];
int temp = 0;
for(int i = 1; i < length; i++)
{
if(dp[i - 1] <= 0)
{
dp[i] = array[i];
}
else
dp[i] = arr[i] + dp[i - 1];
if(dp[i] > maxSum)
{
maxSum = dp[i];
}
}
return maxSum;
}
动态规划的方法,初始化一个最大数组dp[length],这个数字表示arr[m]...arr[n]的数组的和,m会随着dp[i - 1] <= 0这句判断语句而变化,最终得到最大值maxSum。它的简化版就是解法二了。