最大子序和问题
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
贪心算法
分析
若当前指针所指元素之前的和小于0,则丢弃当前元素的序列
例如数组-2,1,-3,4,-1,2,1,-5,4
代码
#include <iostream>
using namespace std;
int Maxsubsum(int nums[],int n)
{
//int maxsum=0;
int maxsum=nums[0];
int presum=0;//之前和
int cursum=0;//当前和
for(int i=0;i<=n;i++){
if(presum<0)//当前元素之前的和小于0,舍弃之前的序列
cursum=nums[i];
else
cursum=presum+nums[i];
presum=cursum;
if(cursum>maxsum)
maxsum=cursum;
}
return maxsum;
}
int main()
{
int num[10]={-2,1,-3,4,-1,2,1,-5,4};
cout<<Maxsubsum(num,8)<<endl;
return 0;
}
效率分析
时间复杂度O(n)
空间复杂度O(1) 只使用了常数空间
动态规划
动态规划是是求解多阶段决策过程的最优化问题一种方法。
基本思想是将一个大问题分为几个子问题,分解得到的子问题不是相互独立的,本方法通过保存子问题的解来改善递归过程每个子问题都需要再求解的问题,避免大量的重复计算
动态规划
分析
若前一个元素大于0,则将其加到当前元素上
相加后或者取当前元素 到一个新的列表,最后取新列表中的最大元素即可
代码
#include <iostream>
using namespace std;
int Maxsubsum(int nums[],int n)
{
int newsum[10];//储存每个子问题的最优解
int maxsum=nums[0];//记录最大子序和
for(int i=0;i<=n;i++){
if(i==0)
newsum[i]=nums[i];
else{
if(newsum[i-1]<0)//前一个和小于0,舍弃前面的序列
{
newsum[i]=nums[i];
}
else{
newsum[i]=nums[i]+newsum[i-1];
}
}
if(newsum[i]>maxsum)
maxsum=newsum[i];
}
return maxsum;
}
int main()
{
int num[10]={-2,1,-3,4,-1,2,1,-5,4};
cout<<Maxsubsum(num,8)<<endl;
return 0;
}
效率分析
时间复杂度O(n)
空间复杂度O(1) 只使用了常数空间
分治法
分治法得基本思想是将一个规模为n的问题分解为k个规模为m的相互独立且与原问题解法相同的子问题,然后将子问题的解合并得到原问题的解。一般要用到递归。
分析
从中心划分,最大子序和或在中心左侧,或在右侧,或跨越中心
代码
#include <iostream>
using namespace std;
int Maxsubsum(int nums[],int left,int right)
{
if(left==right)//数组里只有一个元素
return nums[right];
int mid=(left+right)/2;
int leftsum=Maxsubsum(nums,left,mid);
int rightsum=Maxsubsum(nums,mid+1,right);
int sum=0;
//求中间部分
int s1=0,lefts=0;
//从中间向左侧遍历,求出最大值
for(int i=mid;i>=left;i--){
lefts+=nums[i];
if(lefts>s1)
s1=lefts;
}
int s2=0,rights=0;
//从中间向右侧遍历,求出最大值
for(int i=mid+1;i<=right;i++){
rights+=nums[i];
if(rights>s2)
s2=rights;
}
//将 从中间向两侧求出的最大值 相加,即为跨越中心的最大值
sum = s1 + s2;
//比较 中间最大值,左侧最大值,右侧最大值
if(sum < leftsum)
sum = leftsum;
if(sum < rightsum)
sum = rightsum;
return sum;
}
int main()
{
int num[10]={-2,1,-3,4,-1,2,1,-5,4};
cout<<Maxsubsum(num,0,8)<<endl;
return 0;
}