您的位置:首页 > 职场人生

数组连续子数组最大和最大乘积

2013-07-24 07:18 405 查看
题目:给定一个数组,要求其连续子数组的最大和。如数组为{6,-3,-2,7,-15,1,2,2},连续子数组的最大和为8(从第0个开始,到第3个为止)

解法1:首先最容易想到的便是利用枚举的方法,枚举出所有可能大小的连续子数组的和,然后选出其中最大的一个。即从连续子数组的大小为1一直到n,分别计算它们的和,最后选出使和最大的那个子数组。这种方法的实现比较简单,只需要三重循环即可。然而这种实现方法的复杂度是O(n^3),对于稍微大点的n,运行时间是不可接受的。由于实现方式比较简单,故此没有给出代码。

解法2:很容易理解,当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。基于这样的思路,我们可以写出如下代码。

long getMaxSum(int *arr, int n, int &max_l, int &max_h)
{
if(arr == NULL || n == 0) return LONG_MIN;
long max_sum = LONG_MIN;
long sum = 0;     //子数组当前累加值
 int tmp_l = 0;    //当前累加值的子数组起始索引
int tmp_h = 0;    //当前累加值的子数组终止索引

for(int i = 0; i < n; i++)
{
sum += arr[i];
tmp_h = i;
if(sum > max_sum)
{
max_sum = sum;
max_l = tmp_l;
max_h = tmp_h;
}

if(sum <= 0)
{
sum = 0;
tmp_l = i+1;
tmp_h = i+1;
}
}

return max_sum;
}
变形题目:这个题目有一个变形。数组是首尾相连的,即相当于数组是一个环的结构,要求从这个环的结构中求出最大的和。

解法:当数组是首尾相连时,求连续子数组最大和的方法可以归纳如下:

1.将原数组进行扩充,即假设原数组为{1,2,-3,4,5},则扩充相当于{1,2,-3,4,5,1,2,-3,4,5}

2.利用上述的解法在扩充后的数组进行遍历求其连续子数组的最大和,不过要做一些小改动,即保证子数组的长度在原数组的长度范围之内。这样求出来的结果即是原数组首尾相连后,连续子数组的最大和。

注:当然,此处我们并不需要重新申请一个2倍原数组大小的额外空间,只需要在遍历的时候,下一个索引值采用mod n的方法。具体可以参见源代码。

代码:

/**
*首尾相连连续子数组的最大和
*@param max_l:最终子数组的起始索引
*@param max_h:最终子数组的终止索引
*@return     :返回最大的子数组的和
*/
long getMaxSum(int *arr, int n, int &max_l, int &max_h)
{
if(arr == NULL || n == 0) return LONG_MIN;
if(arr == NULL || n == 0) return LONG_MIN;
long max_sum = LONG_MIN;
long sum = 0;
int tmp_l = 0;
int tmp_h = 0;

for(int k = 0; k < 2*n; k++)
{
int i = k % n;
sum += arr[i];
tmp_h = k;
if(tmp_h - tmp_l + 1 > n)
{
//确保子数组的长度不超过n
sum -= arr[tmp_l%n];
tmp_l++;
}

if(sum > max_sum)
{
max_sum = sum;
max_l = tmp_l;
max_h = tmp_h;
}

if(sum <= 0)
{
sum = 0;
tmp_l = k+1;
tmp_h = k+1;
}
}
return max_sum;
}
扩展:当要求的不是连续子数组的最大和,而是子数组的最大和该怎么求解呢?(提示:动态规划)

题目:给定一个长度为n的数组,其中元素有正有负,求该数组的连续子数组的最大乘积。

解法:本题的解法分析可以参见July的博文:http://blog.csdn.net/v_july_v/article/details/8701148
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息