求最大子序列和(单串动态规划)

72 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

题目描述

给定整型数组,求最大子序列和(单串动态规划)

//输入
nums={-2,1,-3,4,-1,2,1,-5,4}
//输出
6

思路分析

动态规划

基本描述

动态规划解决问题最优解,将原问题划分为若干个子问题,找出最优子结构,进而得出原问题的最优解。注意:当子问题之间存在相同数据的重复计算时可以用动态规划来解决,以便提升代码效率,当子问题间不存在相同数据的重复计算时,可以使用普通递归

f(5)=f(4)+f(3)
f(4)=f(3)+f(2)
//此时重复了f(3)的计算,可以使用动态规划,以便效率提升

难点

  • 理解问题,定义f(n)
  • 通过f(1)....f(n-1)推出f(n),即确定具体的状态方程

具体思路

通过索引值依次遍历数组内的各个值,sum记录访问数组值的和,当访问过的数值和小于当前值的和时,前面的便不再是最大和,接下来从当前值开始记录和;当访问过的数值和大于当前值的和时,记录访问过的数值和+当前值。即,当前最大序列和=max(上一元素最大和,上一元素最大和+当前值)。即当前最优解=max(上一问题最优解,上一问题最优解+当前解)。

//方法实现,此方法不记录最大值索引
int maxSubArray(vector<int> &nums){
int len=nums.size();
vector<int> largest(len);
largest[0]=nums[0];
for(int i=1;i<len;i++){
   largest[i]=max(largest[i-1]+nums[i],nums[i]);
}
return *max_element(largest.begin(),largest.end());
}
//改进,记录最大值索引,返回最大值坐标
    vector<int> maxSubArray(vector<int>& nums) {
        //使最大值等于最小值常量(不能为0,因为数组中可能都是负数)
        int maxsum=INT_MIN,len=nums.size();
        //用来记录最大值坐标
        vector<int> ans(2);
        //记录开始位置
        int begin = 0;
        //sum记录每个子段的和
        int sum=nums[0];
        for(int i=1;i<len;i++){
        //新sum=原sum+当前值,当原sum<0,此时新sum=原sum+当前值<当前值,为了取最大,从当前值开始计算,此时新sum=当前值;如果原sum>0,新sum=原sum+当前值>当前值
            //sum>0时
            if(sum>0)  
                sum+=nums[i];
            //sum<0时
            else{
                //此时sum从位置i的值开始记录,即将nums[i]赋值到sum
                sum=nums[i];
                //当nums[i]自立门户时候,我们记录下子序列的起始位置
                begin=i;     
            }
            if(sum>maxsum){//更新答案
                //依次记录最大和
                maxsum=sum;
                ans[0]=begin;//记录下起始和终止位置
                ans[1]=i;
            }  
        }
        return ans;
    }
};

求最大子数组乘积

   //负数最小乘以负数是最大,正数最大乘以正数是最大
   //输出较大值里面的最大值
   //关键代码
    for(int i=1;i<len;i++){
        large[i]=max(nums[i],max(large[i-1]*nums[i],small[i-1]*nums[i]));
        small[i]=min(nums[i],min(large[i-1]*nums[i],small[i-1]*nums[i]));
    }
    return *max_element(large.begin(),large.end());

知识点补充

max_element()函数:

vector<int> v;
*max_element(v.bedin(),v.end());
//求出vector容器的最大值,将容器从小到大排序,输出最后一个,也就是最大值
*max_element(v.bedin(),v.end());
//求出vector容器的最小值,将容器从小到大排序,输出第一个,也就是最小值
v.begin()       //指向迭代器中第一个元素。   
v.end()         //指向迭代器中末端元素的下一个,指向一个不存在元素。
v.rbegin()      //传回一个vector的最后一个数据的指针。  
v.rend()        // 传回一个vector的第一个数据前一个位置的指针 
v.back()        //获取vector容器的最后一个元素
v[v.size()-1]   //获取vector容器的最后一个元素