算法学习:动态规划
前言
前些天重新看了麻省理工大学算法导论的公开课有关动态规划的讲解,收获很多,这里总结一下我学到的内容。
动态规划(dynamic programming)的主要特性:
- 最优子结构
- 重叠子问题
最优子结构:
一个问题的最优解包含了子问题的最优解
就拿最经典的LCS(最长公共子序列)为例来说,假如一个子序列STR_solution是STR1和STR2的LCS,那么STR_solution的前缀(prefix)序列一定是x的前缀序列和y的前缀序列的一个最优解。
即
假如STR1[1...n-1] 和STR2[1...m-1]的LCS已经得到了,那么我们考察STR1[n]和STR2[m],假如相等,则应该将STR1[n]加入到STR1[1...n-1] 和STR2[1...m-1]的LCS后面形成一个新的LCS。(这是剪贴法,视频中结合反证法证明)
重叠子问题
在划分原问题到子问题的递归过程中会有很多子问题被重复计算(从递归树可以很容易看出来)
在LCS中假设STR1的长度为m,STR2的长度为n,则这个问题的子问题空间有m*n个,为了解决重叠的问题我们可以采用备忘法也就是我们在做算法题的时候遇到的dp[]数组...
Leetcode的一些练习:
-
62 Unique Paths 和 63 Unique Paths Ⅱ,这里贴63的
int uniquePaths(int m, int n) {
int A[m][n]; for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { A[i][j] = 0; } } A[m-1][n-1] = 1; for(int i = m - 1; i >= 0; i--) { for(int j = n - 1; j >= 0; j--) { if(i+1>m-1 && j+1 <= n-1) { A[i][j] = A[i][j+1]; continue; } else if (i+1 <= m-1 && j+1 > n-1) { A[i][j] = A[i+1][j]; continue; } else if (i+1 <= m-1 && j+1 <= n-1){ A[i][j] = A[i+1][j] + A[i][j+1]; } } } return A[0][0];}
-
91 Decode Ways
public class Solution { public int numDecodings(String s) { int n = s.length(); if (n == 0) return 0; int[] memo = new int[n+1]; memo[n] = 1; memo[n-1] = s.charAt(n-1) != '0' ? 1 : 0; for (int i = n - 2; i >= 0; i--) if (s.charAt(i) == '0') continue; else memo[i] = (Integer.parseInt(s.substring(i,i+2))<=26) ? memo[i+1]+memo[i+2] : memo[i+1]; return memo[0]; }}
小结
动态规划本身是一种设计思想,与剪贴法和备忘法不是一码事,在以前做这类问题的时候总是会往Devide & Conquer上面思考,其实这两者某些地方很像,只不过动态规划更加强调子问题解的扩展性,所以现在我在思考dp问题的时候都会有意识去考虑子问题的关联性,从小规模问题出发,然后利用剪贴法的思想去扩张子问题规模来考虑,星期六星期天打算做几道二维dp的再来训练一下。
posted on 2018-03-16 23:40 BlaBlaLogic 阅读(105) 评论(0) 收藏 举报
浙公网安备 33010602011771号