//最大子段和
#include<iostream>
#include<vector>
using namespace std;
//暴力,O(n^2)
void MaxSubarray_brute(vector<int> &nums,int& besti,int& bestj,int &res){
//初始值为足够小
res = INT_MIN;
int n = nums.size();
for (int i = 0; i < n; i++)
{
int sum = 0;
for (int j = i; j < n; j++)
{
sum += nums[j];
if (sum > res)
{
res = sum;
besti=i;
bestj=j;
}
}
}
}
//分治: O(nlogn)
int recur_helper(vector<int> &nums,int low,int high);
void MaxSubarray_recur(vector<int> &nums,int &res){
res=recur_helper(nums,0,nums.size()-1);
}
/*三种情况:
1.MaxSubarray在左半部分
2.MaxSubarray在右半部分
3.MaxSubarray起点在左半部分,终点在右半部分,一定包括中间位置
*/
int recur_helper(vector<int> &nums,int low,int high){
if(low>high)return 0;
if(low==high)return nums[low];
int mid=(low+high)/2;
int leftsum=recur_helper(nums,low,mid);
int rightsum=recur_helper(nums,mid+1,high);
int s1=INT_MIN,s2=INT_MIN,tmp1=0,tmp2=0;
for(int i=mid;i>=low;i--){
tmp1+=nums[i];
s1=max(s1,tmp1);
}
for(int j=mid+1;j<=high;j++){
tmp2+=nums[j];
s2=max(s2,tmp2);
}
int cross_sum=s1+s2;
int res=cross_sum;
res=max(res,leftsum);
res=max(res,rightsum);
return res;
}
//dp: O(n)
void MaxSubarray_dp(vector<int> &nums,int &res){
int n=nums.size();
vector<int> f(n+1);//以nums[i]结尾的最大子序和
f[0]=nums[0];
for(int i=1;i<n;i++){
if(f[i-1]>0)
f[i]=f[i-1]+nums[i];
else//新的开始
f[i]=nums[i];
}
//求最大,可以在上面一起算,单独写方便理解
res=INT_MIN;
for(int i=0;i<n;i++){
res=max(res,f[i]);
}
}
int main(){
vector<int> nums={-2,1,-3,4,-1,2,1,-5,4};
int res=0;
MaxSubarray_recur(nums,res);
cout<<"分治法:"<<res<<endl<<endl;
res=0;
MaxSubarray_dp(nums,res);
cout<<"dp:"<<res<<endl;
return 0;
}
003-1算法笔记【动态规划】最大子段和MaxSubarray
于 2022-04-18 23:32:34 首次发布