算法日记30:leetcode53最大子数组和(DFS->记忆化搜索->DP)

一、题目

在这里插入图片描述

二、题解

1、动态规划解题步骤:

  • 1)重述问题
  • 2)找到最后一步
  • 3)去掉最后一步,问题变成了什么?(原问题答案如何从去掉最后一步推出)
  • 4)考虑边界

2、结合题目具体分析:

在这里插入图片描述
假设选择了 4 4 4这个数,作为最后一个数,那么此时原问题答案为:
在这里插入图片描述
在这里插入图片描述

三、DFS实现

//1、选择一个连续子数组,让其区间和最大
//2、选择了一个数,作为子数组的最后一个数
//3、选择一个数(4之前的数)作为数组中的最后一个数,使得其区间和最大
//答案=选择了之前的某个数的区间和+4
//4、边界->数组结束

1、思路解析:

1)遍历数组,选择一个数 x x x作为区间和的最后一个数,并调用递归函数

	int res=-1e9;
    int n=nums.size();
    for(int i=0;i<n;i++)    //枚举最后一个数
    {
       res=max(res,dfs(nums,i));
    }

2)在选择了 x x x的情况下,往前递归,如果不能往下的话,最大值就应该是它自己

3)边界处理:当遍历完数组,return 0,表示此时递归函数的值为0,随后逐层

	int dfs(vector<int>& nums,int x)
    {
        if(x<0) return 0;
        int ans=-1e9;
        
        //选择x之前的数作为其最后一个数  
        //如果不能往下的话,最大值应该是它自己
        ans=max(nums[x],dfs(nums,x-1)+nums[x]);
        return ans;
    }

2、递归函数解析:

1)在第16行的代码中,这样写是为了实现动态规划中的“选择当前数是否能继续延伸成一个更大的子数组”:

ans=max(nums[x], dfs(nums,x-1)+nums[x]);

解释:

    1. nums[x]:表示如果只选择当前元素 nums[x],那么当前子数组的和就是它本身。
    1. dfs(nums, x-1) + nums[x]:表示如果之前的子数组(由 x-1 索引开始的子数组)能够和当前的 nums[x] 连接起来形成一个更大的子数组,那么就将这个更大的和计算出来。

2)为什么不写成 :ans=max(ans, dfs(nums, x-1) + nums[x]);

是因为在递归的过程中,我们不仅要考虑从前一个元素 x-1 加上当前的元素 nums[x],还需要考虑一个边界情况,即当前元素单独作为一个子数组时,它的最大和就是 nums[x] 本身。因此,我们需要对比这两种情况:

  • nums[x]:当前元素本身作为一个新的子数组;
  • dfs(nums, x-1) + nums[x]:将当前元素加到前一个子数组的和上。

因此,应该用 max(nums[x], dfs(nums, x-1) + nums[x]) 来选择这两种情况中的最大值。

2、代码解析:

//1、选择一个连续子数组,让其区间和最大
//2、选择了一个数,作为子数组的最后一个数
//3、选择一个数(4之前的数)作为数组中的最后一个数,使得其区间和最大
//答案=选择了之前的某个数的区间和+4
//4、边界->数组结束

class Solution {
public:
    int dfs(vector<int>& nums,int x)
    {
        if(x<0) return 0;
        int ans=-1e9;
        
        //选择x之前的数作为其最后一个数  
        //如果不能往下的话,最大值应该是它自己
        ans=max(nums[x],dfs(nums,x-1)+nums[x]);
        return ans;
    }

    int maxSubArray(vector<int>& nums) 
    {
        int res=-1e9;
        int n=nums.size();
        for(int i=0;i<n;i++)    //枚举最后一个数
        {
            res=max(res,dfs(nums,i));
        }
        return res;
    }
};

四、记忆化搜索

1、思路解析

1)在DFS(递归)中,存在着大量的重复计算,因此我们可以使用记忆化搜索来进行优化

2、代码解析:

//1、选择一个连续子数组,让其区间和最大
//2、选择了一个数,作为子数组的最后一个数
//3、选择一个数(4之前的数)作为数组中的最后一个数,使得其区间和最大
//答案=选择了之前的某个数的区间和+4
//4、边界->数组结束

class Solution {
public:
    int mem[200007];
    int dfs(vector<int>& nums,int x)
    {
        if(x<0) return 0;
        int ans=-1e9;
        
        //选择x之前的数作为其最后一个数  
        //如果不能往下的话,最大值应该是它自己
        ans=max(nums[x],dfs(nums,x-1)+nums[x]);
        mem[x]=ans;
        return mem[x];
    }

    int maxSubArray(vector<int>& nums) 
    {
        int res=-1e9;
        int n=nums.size();
        for(int i=0;i<n;i++)    //枚举最后一个数
        {
            res=max(res,dfs(nums,i));
        }
        return res;
    }
};

五、动态规划

1、思路解析:

1)在递归中,我们可以发现限制边界的条件有:

  • 选择了某个数 x x x,作为其子数组的最后一个数

2)因此,我们应该循环枚举 x x x,作为最后一个数,并且改写:DFS方程->动态规划

3)边界处理:dp[0]=nums[0];,表示遍历到第0个数时,最大子数组和为nums[0]

  • x<0时默认为dp[]=0

2、代码解析:

//1、选择一个连续子数组,让其区间和最大
//2、选择了一个数,作为子数组的最后一个数
//3、选择一个数(4之前的数)作为数组中的最后一个数,使得其区间和最大
//答案=选择了之前的某个数的区间和+4
//4、边界->数组结束
const int N=2e5+7;
class Solution {
public:
    int dp[N];  //表示第i个数时,最大子数组和
    // int mem[200007];
    // int dfs(vector<int>& nums,int x)
    // {
    //     if(x<0) return 0;
    //     int ans=-1e9;
        
    //     //选择x之前的数作为其最后一个数  
    //     //如果不能往下的话,最大值应该是它自己
    //     ans=max(nums[x],dfs(nums,x-1)+nums[x]);
    //     mem[x]=ans;
    //     return mem[x];
    // }

    int maxSubArray(vector<int>& nums) 
    {
        int res=-1e9;
        int n=nums.size();
        // for(int i=0;i<n;i++)    //枚举最后一个数
        // {
        //     res=max(res,dfs(nums,i));
        // }
        dp[0]=nums[0];  //边界处理
        for(int i=1;i<n;i++)    //枚举最后一个数
        {
            dp[i]=max(nums[i],dp[i-1]+nums[i]);
        }
        for(int i=0;i<n;i++) res=max(res,dp[i]);    //枚举选择哪个数作为最后一个数值最大
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值