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

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

动态规划是什么?

动态规划(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/

相关推荐
IT_Beijing_BIT24 分钟前
C++ 的常见算法 之一
开发语言·c++·算法
日月星辰cmc28 分钟前
【算法题解】部分洛谷题解(下)
算法
Coisinilove38 分钟前
MATLAB——循环语句
开发语言·算法·matlab
bigbigli_大李1 小时前
C++基础21 二维数组及相关问题详解
数据结构·c++·算法
PPPPPaPeR.2 小时前
TopK问题与堆排序
c语言·开发语言·c++·算法
卡戎-caryon3 小时前
【数据结构】06.栈&&队列
c语言·数据结构·算法·链表
山脚ice3 小时前
【CT】LeetCode手撕—704. 二分查找
算法·leetcode
贱贱的剑4 小时前
【算法】选择排序
算法·rust·排序算法
瑜陀4 小时前
2024.06.30 刷题日记
数据结构·算法·leetcode
Star Patrick4 小时前
*算法训练(leetcode)第二十天 | 39. 组合总和、40. 组合总和 II、131. 分割回文串
c++·算法·leetcode