题目描述:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。
我的解题思路:
现在拿到这一类字符串或者数组的题目,我的第一反应就是先举个例子,想想最笨的解法,然后再去想办法进行更改进。针对上述给出的例子,最直接的想法自然是找出所有的子串。起始元素和子串的长度决定着一个子串,如1开始的子串,长度可以为1-8,一共8个。这种算法是最直观的,时间复杂度是O(N*N*N)。
接下来就要想办法去改进。改进的大思路也很明确:在连续的for循环操作之间建立联系,使得上一次操作的结果可以应用于下一次。针对这个问题,从最简单的情况入手,首先取-5作为子串的起始元素,这时候子串只有一个-5.接下来就是取2位子串的起始元素,这时候,子串长度可以为1或者2.以2为起始元素的子串的和可以视为:max(2+0,2+max(-5)):即要么是元素2自己构成子串,要么是元素2加上以-5开始的sum最大的子串构成新的子串。这样一来,就可以用到动态规划的思路,递归的定义最优值,以自底向上的方式计算出最优值。最后写的程序如下:
#include <iostream>
using namespace::std;
void update_tmp(int * src,int i,int len,int * tmp,int max)
{
int curr_len=len-i;
int pri_len=curr_len-1;
int tmp_max = 0;
for(int j=pri_len-1;j>=0;j--)
{
tmp[j+1]=src[i]+tmp[j];
}
tmp[0]=src[i];
}
void main()
{
//int src[]={1,-2,3,10,-4,7,2,-5};
int src[] = {-1,-2,-3,-4};
int len = sizeof(src)/sizeof(int);
int tmp_max= src[len-1];//存储最后一个元素
int curr_max= src[len-1];
for(int i=len-2;i>=0;i--)
{
if(tmp_max>0)
{
tmp_max=src[i]+tmp_max;
}
else
{
if(tmp_max<src[i])
tmp_max=src[i];
}
if(tmp_max>curr_max)
curr_max=tmp_max;
}
cout << curr_max << endl;
}
其实一开始并没有想到DP的算法,但是写完程序再看看博客,才发现所用的就是动态规划的思想。 博客中所给的算法也是用的动态规划的思想,只是博客中是固定末尾元素,我的程序是固定起始元素而已。