递推算法

363 阅读2分钟

数学归纳法

  1. 验证k0成立
  2. 证明如果ki成立,那么k(i+1)也成立
  3. 联合1和2,证明由 k0 -> kn 成立

求解方法

  1. 确定递推状态 💖

一个函数符号 f(x), 及这个函数的含义描述

一般函数所对应的值,就是要求解的值

  1. 确定递推公式

ki -> k(i+1)

  1. 分析边界条件

k0

  1. 程序实现

递归或者循环

例题

wallsize块墙,涂红、黄、蓝三种颜色,相邻两块墙不重色,另墙为环形,首尾不重色,求方案个数count

求解过程1

  1. f[n][j]=yf[n][j] = y

在不考虑首尾成环的情况下,第一块涂颜色0:

n 为wallsize,代表墙数;j 代表最后一块墙颜色

  1. f[n][j]=k=02f[n1][k](kj)f[n][j] = \sum_{k=0}^{2} f[n-1][k]\quad (k \not= j)

f[1]={100010001}f[1] = \begin{Bmatrix}1 & 0 & 0\\\\0 & 1 & 0\\\\0 & 0 & 1\end{Bmatrix}

f[2]={011101110}f[2] = \begin{Bmatrix}0 & 1 & 1\\\\1 & 0 & 1\\\\1 & 1 & 0\end{Bmatrix}

  1. ans=3(f[n][1]+f[n][2])ans = 3*(f[n][1] + f[n][2])

求解过程2

  1. f[n]=yf[n] = y

n为wallsize,代表墙数

  1. f[n]=f[n1]+2f[n2]f[n] = f[n-1]+2*f[n-2]

考虑第1块和第n-1块墙颜色:

当两块颜色不一样时,第 n 块只有 1 种颜色方案,即第 n-1 块的颜色方案数,f[n1]f[n-1]

当两块颜色一样时,第 n 块有 2 种颜色方案, 即第 n-2 块的颜色方案数乘 2,2f[n2]2*f[n-2]

动态规划

多了决策过程,递归算法中的最优解

状态转移公式重点

  • 状态:一个数学符号、外加一个语义描述
  • 决策:从所有可能产生最优解的状态中,选择最大值
  • 阶段:本阶段只依赖于上一个阶段

列题:三角形最小路径和 (leetcode 120)

求解过程1

来向:从三角底部到顶部,根据下一层的值(还未求出)更新当前层的值

var minimumTotal = function(triangle) {
    let n = triangle.length, dp = new Array(2)
    for (let i=0;i<2;i++) {
        dp[i] = new Array(n).fill(0)
    }
    for (let i=0;i<n;i++) {
        let ind = (n-1) % 2 
        dp[ind][i] = triangle[n-1][i]
    }
    for (i = n-2;i>=0;i--) {
        let ind = i % 2
        let nextInd = 1 - ind
        for (j = 0;j<=i;j++) {
            dp[ind][j] = Math.min(dp[nextInd][j], dp[nextInd][j+1]) + triangle[i][j]
        }
    }
    return dp[0][0]
};

求解过程2

去向:从三角顶部到底部,根据当前的值去更新下一层中受影响的值

var minimumTotal = function(triangle) {
    let n = triangle.length, dp = new Array(n), ans = Number.MAX_SAFE_INTEGER
    for (let i=0;i<n;i++) {
        dp[i] = new Array(i+1).fill(Number.MAX_SAFE_INTEGER)
    }
    dp[0][0] = triangle[0][0]
    for (let i=0;i<n-1;i++) {
        for (let j=0;j<=i;j++) {
            dp[i+1][j] = Math.min(dp[i][j] + triangle[i+1][j], dp[i+1][j])
            dp[i+1][j+1] = Math.min(dp[i][j] + triangle[i+1][j+1], dp[i+1][j+1])
        }
    }
    for (let i=0;i<dp[n-1].length;i++) ans = Math.min(ans, dp[n-1][i])
    return ans
};