oj

Algorithm OJ and Java examples.

View on GitHub

动态规划

解题思路

问题需要满足原则:最优子结构

使用过程中需要确定:

(0)目标

求背包中最大价值

(1)状态

比如0-1背包问题,状态是“背包容量”和“可选择的物品”。

// 状态
for (int i = 1; i < GOODS_NUM; i ++) {
    for (int j = 1; j < BAG_CAP; j ++) {
        // 做选择
    }
}

(2)选择

// 状态
for (int i = 1; i < GOODS_NUM; i ++) {
    for (int j = 1; j < BAG_CAP; j ++) {
        // 做选择
        dp[i][j] = max 价值 (物品i放进背包, 物品i不放进背包)
    }
}

典型问题

子序列问题

模板


int	n = arr.length;
int[][] dp = new dp[n][n];
for	(int i = 0; i < n; i++) {
    for	(int j = 0; j < n; j++) {
    if	(arr[i] == arr[j])	
        dp[i][j] = dp[i][j]	+ ...
    else
        dp[i][j] = 最值(...)
    }
}

(1)涉及到两个字符串

LeetCode 1143 最长公共子序列(LCS, Longest Common Subsequence)

最长公共子序列

dp[i][j]的含义是:对于s1[1..i]s2[1..j],它们的LCS⻓度是dp[i][j]

(2)涉及一个字符串

LeetCode 516 最⻓回文子序列(LSI)

最长回文子序列

最长回文子序列

备忘录(数组)形式的动态规划

0-1背包问题

完全背包问题

子集背包问题

最长公共子序列

最长公共子序列就是一个典型的“dp的状态转移矩阵只依赖于之前的结果”的情况。所以可以使用递归+动态规划方式,也可以使用数组的方式。

递归 + 动态规划

扔鸡蛋问题

使用递归的方式实现动态规划

不能使用数组的原因:不能使用数组形式实现的原因是某一个dp需要依赖的其他dp可能还没有计算出来。比如,

dp[i][j] = max(dp[i - 1][N - j], dp[i][j - 1])

我们这里可能无法知道dp[i - 1][N - j]或者dp[i][j - 1],所以也就无法得到这个结果了。如果采用递归/回溯的方式,则可以得到任意的dp。然后将该DP结果保存到hash map中就可以起到备忘录的效果。

怎么样的情况才能使用数组形式的dp呢?应该是

dp的状态转移矩阵只依赖于之前的结果(见最长公共子序列),比如

dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])