动态规划简述

动态规划经典题目之最大子序和

​ 最近在学习动态规划算法,通过一道经典例题:最大子序和(力扣-53题)来分享一下动态规划的算法思想。

一、什么是动态规划

​ 动态规划(Dynamic Programming)是一种大事化小、小事化无的解决问题方式。在将大规模问题化解为小规模问题的过程中,保存对每个小规模问题的处理结果,这样在后面处理大规模问题时,可以直接使用这些小规模问题的结果。

二、动态规划的特点

动态规划具备下列三个特点

  1. 把原来的问题分解成几个相似的子问题
  2. 所有的子问题都只需要解决一次
  3. 存储子问题的解。

三、动态规划的解决方法

​ 首先我们考虑写出一个子问题状态的定义设置为f(n),对第一个子问题求解,就是f(1),对第二个子问题求解就是f(2)···这里对状态定义的要求就是:一定要形成递推关系

​ 接下来利用前i - 1个f(n),通过一个式子求出第i个状态的结果,即f(i) = f(f(1),f(2),···f(i - 1)),这个式子就是状态转移方程,我们在思考如何用f(1)…f(n -1)求出f(n)的过程实际就是在列出状态方程的过程。

下面利用题目进行实战尝试,题目描述及示例如下:

image-20211115113741430

假设整数数组nums的长度是n,那么其下标为0~n-1。首先定义出状态,f(i)代表nums数组以第i个数字作为结尾时连续子数组的最大和,那我们的结果肯定是:
m a x ( f ( 0 ) . . . f ( n − 1 ) ) max(f(0)...f(n - 1)) max(f(0)...f(n1))
所以我们只需要求出每个位置的f(i),然后返回其中最大的那个就是我们所需要的结果。

那么如何求出f(i)呢?

我们可以将nums[i]这个数字与它和前面第(i - 1)个解之和进行比较,取两者之间更大的那个,因此状态转移方程应该是:
f ( i ) = m a x ( f ( i − 1 ) + n u m s [ i ] , n u m s [ i ] ) f(i) = max(f(i - 1) + nums[i], nums[i]) f(i)=max(f(i1)+nums[i],nums[i])
这里也很好理解,如果f(i - 1) + nums[i]的和更大,那么nums[i]就加入这个子序列,变成目前最大的子序列,如果两者之和还没有nums[i]自己大,那就另起炉灶,将nums[i]这个数字作为数组以i为结尾连续子数组的最大和。

代码如下:

class Sloution{
public:
    int maxSubArray(vector<int>& nums){
        int n = nums.size();
        vector<int>dp(n,0);//构造一个与nums数组一样长的dp数组,用来存放子数组的最大和
        dp[0] = nums[0];//以第一个数字为结尾的最大子序列和只能是它本身,这是状态的初始化部分
        int ret = nums[0];//ret用来存放dp数组中最大的值
        for(int i = 1; i < n; i++){
            dp[i] = max(dp[i - 1] + nums[i], nums[i]);//当前以i为结尾的连续最大子序列的和
            if(ret < dp[i]){
                ret = dp[i];//也可不设置ret变量,最后将dp数组遍历一遍找到最大值,但是会多进行一次规模为N的循环。
            }
        }
        return ret;
    }
    
};

总结:

动态规划问题需要考虑的重点是:

  1. 如何定义状态,即f(i);
  2. 如何写出状态间的状态转移方程,即如何用f(1)···f(i - 1)表示出f(n);
  3. 状态的初始化,即注意边界部分;
  4. 勤加练习,多多总结。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值