动态规划法(JavaScript)

目录

一、动态规划

二、性质

三、典型问题

四、求解的基本步骤

五、案例

1、爬梯子问题

2、最大和的连续子数组


一、动态规划

动态规划(简称DP)的思想是把一个大的问题进行拆分,细分成一个个小的子问题,且能够从这些小的子问题的解当中推导出原问题的解。

二、性质

1、最优子结构性:既所拆分的子问题的解是最优解

2、无后效性:即子问题的解一旦确定,就不再改变,不受在这之后、包含它的更大的问题的求解决策略影响。

3、子问题重叠性质:既在求解的过程当中,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的解题效率。

三、典型问题

1、斐波那契数列

const f = new Array()
function dp(n)
{
    f[1] = 1;f[2] = 1;
    for(let i = 3;i <= n ;i ++)
        f[i] = f[i-1] + f[i-2];
}
console.time('time')  //算法的开始时间
dp(50)
console.timeEnd('time') //算法的结束时间

let str = ""
for(let i=3;i<f.length;i++){
    str += f[i]+"\t"
}
console.log(str)
//输出结果:time: 0.182ms
//2       3       5       8       13      21      34      55      89      144     //233
//377     610     987     1597    2584    4181    6765    10946   17711   28657   46368       //75025   121393  196418  317811  514229  832040  1346269 2178309 3524578 5702887     //9227465 14930352        24157817        39088169        63245986        102334155   //165580141       267914296       433494437       701408733       1134903170 1836311903       //2971215073      4807526976      7778742049      12586269025

四、求解的基本步骤

 动态规划所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条活动路线(通常是求最优的活动路线)。 

初始状态→│决策1│→│决策2│→…→│决策n│→结束状态

1、划分阶段按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。

2、确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。

3、确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程。

4、寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。

五、案例

1、爬梯子问题

假设你正在爬楼梯,需要 n 阶你才能到达楼顶。每次可以爬1或2阶台阶,可以有多少种不同的方法爬到楼顶

假设,我求5阶台阶有多少种上法;五级台阶可以是走一阶台阶加上四阶台阶的种类,和走二阶台阶加上三阶台阶的种类,这样就是五阶台阶的上法等于四阶台阶的上法加上三阶台阶的上法。

//爬楼梯问题
function climbStairs(n) {
    if (n === 1 || n === 2) {
        return n;
    }

    var ways = [];
    ways[0] = 1;
    ways[1] = 2;
    for(var i=2; i<n; i++){
        ways[i]=ways[i-1] + ways[i-2];
    }
    return ways[n-1];
}
console.log(climbStairs(3));//3

2、最大和的连续子数组

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

示例:输入:[-2,1,-3,4,-1,2,1,-5,4]           输出:6

解释:连续子数组[4,-1,2,1]的和最大为6

function maxSubArray(nums) {    
    let dp = new Array(nums.length);
    //初始化数据
    dp[0] = nums[0];
    let ans = nums[0];

    for(let i = 1; i < nums.length; i ++){
        //获取以nums[i]结尾的最大值
        dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
        //记录最大值
        if(dp[i] > ans) ans = dp[i];
    }
    return ans;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值