剑指offer:连续子数组的最大和
题目描述:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)。
这个题目描述好长啊。。。。简单的说就是:给你一个数组,让你得到其中的一个连续子数组,这个子数组具有最大的和。
本菜鸡的想法
最一开始最容易想到的肯定是枚举没错了,计算一下所有连续子数组的和,保留最大的。
但这个枚举过程也有一些可以轻易剪掉的分支:以负数为开头的所有连续子数组都可以不用枚举。
但这有一个问题,就是所有的数都是负数呢?所以我设置了一个标志位,如果所有的都是负数,就返回最大负数。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int FindGreatestSumOfSubArray(vector<int> array)
{
if (array.size() == 0)
{
return 0;
}
int res = 0,Max=-9999999;
int flag = 0, tmp = -9999999;
for (int i = 0; i < array.size(); i++)
{
if (array[i] < 0)
{
tmp = max(tmp, array[i]);
continue;
}
else
{
flag = 1;
for (int j = i; j < array.size(); j++)
{
res += array[j];
Max = max(Max, res);
}
}
res = 0;
}
if (flag == 0)
{
return tmp;
}
else
{
return Max;
}
}
int main()
{
vector<int> vec = { -2,-8,-1,-5,-9 };
int res = FindGreatestSumOfSubArray(vec);
cout << res;
}
这种方法不太好,看了别人的方法用的是动态规划
动态规划
首先,状态表示 F[i] ,表示的是以第i个元素结尾的具有最大和的子数组的和。
状态转移方程:F[i] = max(F[i-1]+array[i],array[i])
为什么F[i]要这么定义?最终得到的结果肯定是以某个元素结尾的子数组,所以F[i]定义为 以第i个元素结尾的具有最大和的子数组的和 ,这样,找到所有的F[i]后再找最大的就是答案了。
为什么状态转移方程是这样?F[i]是与F[i-1]有关系的,但F[i-1]可能是负的呀,所以要是负的的话,那还不如自己自成一个子数组。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int FindGreatestSumOfSubArray(vector<int> array)
{
if (array.size() == 0)
{
return 0;
}
int res = array[0]; //res是用来存储F[i-1]
int Max = array[0]; //max是用来存当前状态下的最大值。
for (int i = 1; i < array.size(); i++)
{
res = max(res + array[i], array[i]);
Max = max(Max, res);
}
return Max;
}
int main()
{
vector<int> vec = {6,-3,-2,7,-15,1,2,2};
int result = FindGreatestSumOfSubArray(vec);
cout << result;
}