动态规划

简介

动态规划(Dynamic Programming)也叫DP算法,通常用于求解具有某种最优性质的问题。其基本思想就是将一个复杂的问题分解若干个简单的子问题,而这些子问题相互之间不是独立的,每个子问题仅仅只解决一次。我们可以使用一块额外的空间(例如数组)来记录所有已解的子问题的答案,不管这个子问题以后是否会被用到,都会记录到这个空间中。

基本概念

首先我们来说明以下几个概念,
状态:状态可以理解为原问题和简单的子问题的解。
这时,我们需要根据子问题的状态的推导出原问题的状态,也就是推导出状态转移方程
状态转移方程:从i-1状态转移到i状态的状态转移规律,用一个公式展示出来。
例如DP[i] = DP[i-1] +1;

解题步骤

动态规划的问题的基本步骤如下:
1,动态规划顾名思义,就是变化的状态的规划。所以我们得首先定义一个状态,即定义最优解的状态
2,确定状态转移方程
3,设置初始状态(设置边界值)

适用条件

任何思想和算法都有一定的局限性,超出了特定条件,它就失去了作用。同样,动态规划也并不是万能的。适用动态规划的问题必须满足最优化原理和无后效性。

最优化原理
  1. 最优化原理:通过求解子问题的最优解,可以获得原问题的最优解
  2. 无后效性:某阶段的状态一旦确定,此后的过程的演变不在受此前各状态及决策的影响(未来与过去无关)。在推导后面阶段的状态时,只关心前面阶段的具体状态值,不关心这个状态是怎么一步步推导出来的。

例题分析

我们选择leetcode上的一道题来分析,来帮助大家更加深入的了解动态规划算法的原理以及使用。

题目概述

最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

题目分析

根据动态规划的解法,我们解题步骤分为以下几步:

定义状态

假设dp(i)是以nums[i]为结尾的最大子序和(nums为整个数组)。那么数组nums(长度为n)的最大子序列为dp(1)到dp(n)的最大值,那么问题就转化为求出dp(i)。

状态转移方程

dp(i-1)表示以nums[i-1]的值为结尾的最大子序和,那么我们得出以下的公式,当dp(i-1) <= 0 时,dp(i) = nums[i],当dp(i-1) >0时,dp(i) = dp(i-1) +nums[i];

边界值
//没有dp(-1),所以先给dp(0)赋值,i从1开始
dp(0) = nums[0];
代码
  if (nums == null || nums.length == 0) return 0;
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int max = dp[0];
        for (int i = 0; i < dp.length; i++) {
            if (dp[i - 1] <= 0) {
                dp[i] = nums[i];
            } else {
                dp[i] = dp[i - 1] + nums[i];
            }
            max = Math.max(dp[i], max);
        }
        return max;
优化

上面的代码我们使用一个额外的数组来保存dp(i),但是我们通过状态转移方程可以发现,dp(i)的状态只跟dp(i-1)的状态有关,所以我们只需使用一个额外的变量来保存dp(i-1)即可。

  int pre = nums[0];
        int max = nums[0];
        for (int i=1;i < nums.length; i++) {
            pre = Math.max(pre+nums[i],nums[i]);
            max = Math.max(pre,max);
        }
        return max;

原文链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值