剑指offer--连续子数组的最大和

题目描述

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

#include<iostream>

#include<vector>

using namespace std;



class Solution {

public:

int FindGreatestSumOfSubArray(vector<int> array) {

int max = -2147483648;

int i = 0;

int size = array.size();

for (i = 0; i <= size - 1; i++)

{

int m = i ;

int sum = 0;

int max1 = -2147483648;

for (; m <=size - 1; m++)

{

sum = sum + array[m];

if (sum>max1)

{

max1 = sum;

}

}

if (max1 > max)

max = max1;

}

return max;

}

};

 

这是我通过暴力求解的算法来得出的结果,先从第一个数据开始不断的向后加,先找到第一个数据最大区间,然后找第二个数据第三个数据找出来里边最大的那个就是我们的最大和,也就是说把整个数组所有的子数组和的情况都求解然后最后找出来最大的那一个,但是这肯定是最笨最慢的一种方法。这是有几个需要注意的地方,就是我们的max和max1不能设定为0,我在第一次编译的时候就发现有一部分没通过,发现他给的程序用例里边全都是负数,这样你返回的值就是0 了但是人家是负数,就有问题了,所以这里我设定的是int类型的最小值,其实还有一种方法就是直接让你的max等于数组第一个数据,这样也是可以的。自己在写代码的时候没有想到。

  下边说一下我看到的其他人的代码。

class Solution {

public:

int FindGreatestSumOfSubArray(vector<int> array) {

if (array.empty()) return 0;

int max_s = array[0];

int sum = array[0];

for (int i = 1; i < array.size(); ++i){

sum += array[i];

max_s = max(max_s, sum);

sum = max(sum, 0);

}

return max_s;



}

};

这里的max是系统的函数,直接调用就可以但是是需要包含#include <algorithm>  头文件的。这个程序前边都比较容易理解,这里他把最大值和和都先设定成了我们的array[0],就不需要设置int类型最小值了。通过for循环来不断的相加,和就是不断的往后加,然后判断一下当前所得到的和,之前的最大值那个大,如果是现在的和比较大,那就让现在的和变成最大值。但是下边这一句sum = max(sum, 0);我想了很久不太明白是为什么, 然后在牛客网去掉之后编译了几遍,看失败的错误用例大概能看出了一些门道。

测试用例:[1, -2, 3, 10, -4, 7, 2, -5]

对应输出应该为 : 18

你的输出为 :17

其实这里他和我的程序套路是不一样的,虽然看着都是在相加求最大值,但是有个很明显的区别他只用到了一个for循环,他应该是这样想的,如果我现在从某个位置开始,他之前的那些数据和是负数,那我还要他们干啥要了无论我是正还是负都是让我的数值变小,所以我就不要他们了,我这里就是个新的起点,sum和就是0,之前的那些都不要了。最初我想到这个的时候认为这样是有bug的,你不要前边的那很有可能是三个数据相加和是负数,你都不要了, 他可能是-10,5,4,这样你应该要5和4啊不能三个都不要了吧,这种情况是不存在的,因为如果是这样的话在到5的时候你的-10也就是他的前边你已经不要了。

   这是一个动态规划的程序,之前只是简单的听说过,了解过一点动态规划的内容,但是并不理解什么时候要去使用动态规划,怎么使用。

  这里再放一个别人动态规划求解这个题的代码和简单思路,之后我会写博客介绍动态规划到底是什么,怎么使用的。

使用动态规划

F(i):以array[i]为末尾元素的子数组的和的最大值,子数组的元素的相对位置不变

F(i)=max(F(i-1)+array[i] , array[i])

res:所有子数组的和的最大值

res=max(res,F(i))

 

如数组[6, -3, -2, 7, -15, 1, 2, 2]

初始状态:

    F(0)=6

    res=6

i=1:

    F(1)=max(F(0)-3,-3)=max(6-3,3)=3

    res=max(F(1),res)=max(3,6)=6

i=2:

    F(2)=max(F(1)-2,-2)=max(3-2,-2)=1

    res=max(F(2),res)=max(1,6)=6

i=3:

    F(3)=max(F(2)+7,7)=max(1+7,7)=8

    res=max(F(2),res)=max(8,6)=8

i=4:

    F(4)=max(F(3)-15,-15)=max(8-15,-15)=-7

    res=max(F(4),res)=max(-7,8)=8

以此类推

最终res的值为8

public  int FindGreatestSumOfSubArray(int[] array) {

int res = array[0]; //记录当前所有子数组的和的最大值

int max = array[0];   //包含array[i]的连续数组最大值

for (int i = 1; i < array.length; i++) {

max = Math.max(max + array[i], array[i]);

res = Math.max(max, res);

}

return res;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值