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

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

动态规划是什么?

动态规划(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全部遍历一遍,然后取最大值后返回

算法实现代码

java 复制代码
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/

相关推荐
乐迪信息1 小时前
乐迪信息:基于AI算法的煤矿作业人员安全规范智能监测与预警系统
大数据·人工智能·算法·安全·视觉检测·推荐算法
hsjkdhs2 小时前
C++之多层继承、多源继承、菱形继承
开发语言·c++·算法
立志成为大牛的小牛2 小时前
数据结构——十七、线索二叉树找前驱与后继(王道408)
数据结构·笔记·学习·程序人生·考研·算法
星空下的曙光2 小时前
Node.js crypto模块所有 API 详解 + 常用 API + 使用场景
算法·node.js·哈希算法
StarPrayers.4 小时前
旅行商问题(TSP)(2)(heuristics.py)(TSP 的两种贪心启发式算法实现)
前端·人工智能·python·算法·pycharm·启发式算法
爱吃橘的橘猫4 小时前
嵌入式系统与嵌入式 C 语言(2)
c语言·算法·嵌入式
235164 小时前
【LeetCode】146. LRU 缓存
java·后端·算法·leetcode·链表·缓存·职场和发展
weixin_307779135 小时前
使用Python高效读取ZIP压缩文件中的UTF-8 JSON数据到Pandas和PySpark DataFrame
开发语言·python·算法·自动化·json
柳安忆5 小时前
【论文阅读】Sparks of Science
算法
web安全工具库6 小时前
从课堂笔记到实践:深入理解Linux C函数库的奥秘
java·数据库·算法