详谈动态规划问题并解最大子数组和

今天刷力扣又学会了一种算法----动态规划,经过我查阅不少资料后,这些我总结的分享给大家

动态规划是什么?

动态规划(Dynamic Programming)是一种求解最优化问题的数学方法,它通常用于解决具有重叠子问题和最优子结构性质的问题。动态规划的基本思想是将原问题拆解成若干个子问题,然后通过求解子问题的最优解来得到原问题的最优解。

动态规划有两个关键概念:重叠子问题和最优子结构。

  1. 重叠子问题: 在动态规划中,原问题可以被拆解成多个具有相同结构的子问题,而这些子问题可能会被多次求解。动态规划通过存储已解决的子问题的解,避免重复计算,提高效率。

  2. 最优子结构: 问题的最优解可以通过子问题的最优解来构造。也就是说,问题的整体最优解是由各个子问题的最优解组合而成的。这使得我们可以通过求解子问题来逐步推导出原问题的最优解。

动态规划算法的一般步骤如下:

  1. 定义状态: 描述问题局部最优解的变量,这些变量可以表示问题的不同方面。

  2. 找到状态转移方程: 定义各个状态之间的关系,即问题的最优解如何由子问题的最优解推导而来。

  3. 初始化: 给定问题的初始状态,通常是问题规模较小时的情况,然后逐步扩展规模。

  4. 递推计算: 利用状态转移方程,从初始状态开始逐步计算得到问题的最优解。

  5. 解决原问题: 根据计算得到的最优解,得到原问题的最优解。

动态规划常被用于解决许多问题,如最短路径问题、背包问题、编辑距离问题等。这种方法在解决那些可以被拆解成子问题,并且这些子问题存在重叠的情况下特别有效。

如果觉得以上说法不是太通俗理解我们可以一边结合题,一边来详解什么是动态规划!

使用动态规划求解最大子数组和

先给出一个算法题(摘自力扣)

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

 理解题意:

题目要我们找出和最大的连续子数组的值是多少,「连续」是关键字,连续很重要,不是子序列。

题目只要求返回结果,不要求得到最大的连续子数组是哪一个。这样的问题通常可以使用「动态规划」解决。

如何定义子问题(定义状态)

我们 不知道和最大的连续子数组一定会选哪一个数,那么我们可以求出 所有 经过输入数组的某一个数的连续子数组的最大和。

经过分析,我们列出子问题如下:

子问题 1:以 −2 结尾的连续子数组的最大和是多少;
子问题 2:以 1 结尾的连续子数组的最大和是多少;
子问题 3:以 −3 结尾的连续子数组的最大和是多少;
子问题 4:以 4 结尾的连续子数组的最大和是多少;
子问题 5:以 −1 结尾的连续子数组的最大和是多少;
子问题 6:以 2 结尾的连续子数组的最大和是多少;
子问题 7:以 1 结尾的连续子数组的最大和是多少;
子问题 8:以 −5 结尾的连续子数组的最大和是多少;
子问题 9:以 4 结尾的连续子数组的最大和是多少。

我们单独看子问题 1 和子问题 2:

子问题 1:以 −2 结尾的连续子数组的最大和是多少;
以 −2结尾的连续子数组是 [-2],因此最大和就是 −2。

子问题 2:以 1 结尾的连续子数组的最大和是多少;
以 1 结尾的连续子数组有 [-2,1] 和 [1] ,其中 [-2,1] 就是在「子问题 1」的后面加上 1 得到。−2+1=−1<1 ,因此「子问题 2」 的答案是 1。

大家发现了吗,如果编号为 i 的子问题的结果是负数或者 0 ,那么编号为 i + 1 的子问题就可以把编号为 i 的子问题的结果舍弃掉(这里 i 为整数,最小值为 1 ,最大值为 8),这是因为:

一个数 a 加上负数的结果比 a 更小;
一个数 a 加上 0的结果不会比 a 更大;
而子问题的定义必须以一个数结尾,因此如果子问题 i 的结果是负数或者 0,那么子问题 i + 1 的答案就是以 nums[i] 结尾的那个数。

定义状态(定义子问题)

dp[i]:表示以 nums[i] 结尾的连续子数组的最大和。

「结尾」和「连续」是关键字。

状态转移方程(描述子问题之间的联系)
根据状态的定义,由于 nums[i] 一定会被选取,并且以 nums[i] 结尾的连续子数组与以 nums[i - 1] 结尾的连续子数组只相差一个元素 nums[i] 。

假设数组 nums 的值全都严格大于 0,那么一定有 dp[i] = dp[i - 1] + nums[i]。

可是 dp[i - 1] 有可能是负数,于是分类讨论:

如果 dp[i - 1] > 0,那么可以把 nums[i] 直接接在 dp[i - 1] 表示的那个数组的后面,得到和更大的连续子数组;
如果 dp[i - 1] <= 0,那么 nums[i] 加上前面的数 dp[i - 1] 以后值不会变大。于是 dp[i] 「另起炉灶」,此时单独的一个 nums[i] 的值,就是 dp[i]。
以上两种情况的最大值就是 dp[i] 的值,写出如下状态转移方程:

dp[i]=\left\{\begin{matrix} dp[i-1]+nums[i],if & dp[i-1]>0 & & \\ nums[i], if &dp[i-1]\leqslant 0 \end{matrix}\right.

输出:

注意:这里状态的定义不是题目中的问题的定义,不能直接将最后一个状态返回回去

我们需要将之前的dp全部遍历一遍,然后取最大值后返回

算法实现代码

class Solution {
    public int maxSubArray(int[] nums) {
        int len = nums.length;
        int [] dp=new int[len];
        dp[0]=nums[0];
        for(int i=1;i<len;i++){
            if(dp[i-1]<0){
                dp[i]=nums[i];
            }else{
                dp[i]=dp[i-1]+nums[i];
            }
        }
        int res=dp[0];
        for(int i=1;i<len;i++){
            res=Math.max(res,dp[i]);
        }
        return res;
    }
}

算法思路转载来源:力扣(LeetCode)

作者:liweiwei1419
链接:https://leetcode.cn/problems/maximum-subarray/

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
静态库和动态库在编译和运行时的行为有所不同。静态库在程序编译时会被连接到目标代码中,而动态库则是在程序运行时才被载入。 静态库对应的lib文件叫做静态库,而动态库对应的lib文件叫做导入库。静态库本身包含了实际执行代码、符号表等信息,而导入库只包含了地址符号表等,用于确保程序能够找到对应函数的基本地址信息。\[1\] 静态库的大小通常比较大,因为它包含了实际执行代码和其他必要的信息。而动态库的大小相对较小,因为它只包含了地址符号表等基本信息。\[1\] 使用静态库的程序在编译时会将静态库的代码复制到最终的可执行文件中,因此可执行文件会比较大。而使用动态库的程序在编译时只会包含对动态库的引用,而不会将动态库的代码复制到可执行文件中。这样可以减小可执行文件的大小,并且多个应用程序可以共享同一个动态库的实例,避免了空间浪费。\[3\] 另外,动态库的使用还解决了静态库对程序的更新、部署和发布带来的麻烦。当需要更新动态库时,只需要替换动态库文件即可,而不需要重新编译整个程序。这样可以实现增量更新,方便程序的维护和升级。\[3\] 综上所述,静态库和动态库的主要区别在于编译时和运行时的行为不同,静态库在编译时被连接到目标代码中,而动态库在程序运行时才被载入。此外,静态库会增加可执行文件的大小,而动态库可以实现共享和增量更新。 #### 引用[.reference_title] - *1* *2* [静态库和动态库的区别](https://blog.csdn.net/sinat_16643223/article/details/114027857)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [详谈静态库和动态库的区别](https://blog.csdn.net/weixin_71478434/article/details/126588174)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆粉今天敲了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值