input: 一个整数数组 A[],假设其长度为n
output:一个连续子数组的最大和 (int),answer
《算法设计与分析》黄宇(题目3.9):最大和连续子序列
给定一个由整数组成的序列nums[],请找出和最大的连续子序列。例如,nums={-2,11,-4,13,-5,-2},得到的结果应为20=11-4+13
1)你可以基于简单遍历数组元素,设计一个O(n^3)的算法
指针i从0-n扫描遍历,指针j从0-i扫描遍历
指针k从j-i扫描依次加和
int sumi[n];
int Max_i=nums[0];
for(int i=0;i<n;i++){
int sumj[i];
//求j-i使得和最大的那个j
int max=sumj[0];
for(int j=0;j<i;j++){
for(int k=j;k<=i;k++){
sumj[j]+=nums[k];
}//j->i的k循环
if(sumj[j]>max) max=sumj[j];
}//0->i的j循环
sumi[i]=max;
if(sumi[i]>Max_i) Max_i=sumi[i];
}
return Max_i;
2)改进上述算法中的冗余计算,你可以得到一个基于遍历的O(n^2)的算法
3)基于分治策略,你可以设计一个O(nlogn)的算法
4)分析遍历算法中的冗余计算,你可以设计一个O(n)的算法
5)基于动态规划策略,你同样可以得到一个O(n)的动态规划算法
For this DP problem,I will try ‘SRTBOT’:
S-子问题定义
分析:输入为一个一维int序列,那么我假设子问题的规模也是一维的
try preffix[]:
定义P(k)为A[1.....k]数组的最大和连续子序列的和(is an number)
R-子问题的递归关系
1.第A[i]个元素包含于P(i)最大子序列中:
则P(i)=以元素A[i]结尾的所有连续子序列中,最大的那一个,即
P(i)=max{
A[i],
A[i]+A[i-1],
A[i]+A[i-1]+A[i-2],
.......,
A[i]+A[i-1]+A[i-2].....+A[2]+A[1]
}
由于我们不知道是这i个序列中的具体哪一个,所以我们设一个指针j从1->i依次扫描,声明一个辅助变量S(i,j)[n][i],它是一个以i,j分别为维度的二维数组,一共n行,每行有i列(i=1,2,3,...n);
设S(i,j)[i][j]=A[j]+....+A[i];
固定i时,数组元素依次为:
A[i]+A[i-1]+A[i-2].....+A[2]+A[1]、
A[i]+A[i-1]+A[i-2].....+A[2]、
A[i]+A[i-1]+.....+A[3]、
.....、
A[i-1]+A[i]、
A[i].
另外写一个函数int GetMaxArray(),用来求S(i,j)[][]数组里第i行的最大值,最大值记为Max_Sum_i;
//StartTag_j用来记录最长子序列的第一个下标
int GetMaxArray(& a[]){
//传入数组a[]
int len=sizeof(a);
int Max_Sum_i=a[0];
for(int k=0;k<len;k++){
if(a[k]>Max_Sum_i)
{Max_Sum_i=a[k];
StartTag_j=k;}
}
return Max_Sum_i;
}
2.第A[i]个元素不在P(i)中,则
P(i)=P(i-1)
3.综合1.2 ----> 得到整体的递归式
P(i)=max{ Max_Sum_i , P(i-1) }
T-子问题调度的拓扑顺序
i从0一直增加到n
B-递归基
P(0)=A[0]
O-要求问题:goal
P(n)
T-时间分析
还未仔细调整的初步C++实现
int dp[n];//用来记录子问题的解
dp[0]=A[0];//B-asecase;
int S[n][];
for(int i=1;i<n;i++){
for(int j=0;j<=i;j++){
//此时i是固定的
for(int k=j;k<=i;k++){
S[i][j]+=A[k];
}//k的循环结束
}//j的循环结束
dp[i]=Max{dp[i-1],Get_Sum_Max(S[i][])};
//此处可以用冒号表达式
}
return dp[n];
/*以下是我第一次做leetcode53时总报错栈溢出的版本
也就是递归调用了maxSubArray函数
暂时不知道具体的问题出在哪里
之后我会回来解决
*/
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//声明一个数组S来 储存子问题的解
int n=sizeof(nums);
int S[n];
//定义递归基
S[0]=nums[0];
if(n==0) return 0;
if(n==1) return nums[0];
//
for(int i=1;i<=n;i++){
vector<int> copyi(nums.begin(),nums.begin()+i);
vector<int> copyi1(nums.begin(),nums.begin()+i-1);
if(maxSubArray(copyi)<maxSubArray(copyi1)+nums[i])
{
S[i]=S[i-1]+nums[i];
}else{
S[i]=S[i-1];
}
}
return S[n-1];
}
};
最后待修正代码
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//声明一个数组S来 储存子问题的解
long int n=sizeof(nums);
long int dp[n];
//定义递归基
dp[0]=nums[0];
if(n==0) return 0;
if(n==1) return dp[0];
//
long int MAX_SUM=0;
for(int i=1;i<n;i++){
long int Sum_i=0;
for(int j=i-1;j>=0;j--){
Sum_i=Sum_i+nums[j];
}
if(MAX_SUM<Sum_i) MAX_SUM=Sum_i;
dp[i]=max(MAX_SUM,dp[i-1]);
}
return dp[n-1];
}
};