目录:
- 面试中常见的动态规划类型
- 坐标型动态规划
1.1 题目 - 最小路径和(求最大最小值)
1.2 题目 - 不同的路径(统计方案个数)
1.3 题目 - 爬楼梯 (统计方案个数、一维坐标上的dp)
1.4 题目 - jump game (是否可行、一维坐标上的dp - follow up:求最小值)
1.5 题目 - 最长上升子序列 (最大最小值) - 序列型动态规划
2.1 题目 - word break (可行性)
2.2 题目 - 切割回文串 palindrome-partitioning-ii (最大最小值)- 判断回文串(区间型动态规划) - 双序列型动态规划
3.1 题目 - 最长公共子序列(求Max)
3.2 题目 - Edit Distance (求Min)
3.3 题目 - Distinct Subsequence (求方案总数)
3.4 题目 - Interleaving String (求是否可行) - 其他类型的动态规划
0.面试中常见的动态规划类型
1.坐标型动态规划
初始化一个二维的动态规划的时候,首先初始化起点,紧接着初始化第0行和第0列。
1.1最小路径和
1)题目
http://www.lintcode.com/zh-cn/problem/minimum-path-sum/
给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径。
2)思路
如果是上下左右四个方向都可以走,则不能用dp,因为四个方向的话存在环,这样就不能定义远近关系,也就是不能定义大状态和小状态,就没法定义递推方程。但也存在例外,比如说滑雪的题目,按照数值降低定义远近关系。
class Solution {
public:
/*
* @param grid: a list of lists of integers
* @return: An integer, minimizes the sum of all numbers along its path
*/
int minPathSum(vector<vector<int>> &grid) {
// write your code here
int n = grid.size();
if(n==0){
return 0;
}
int m = grid[0].size();
vector<vector<int>> dp(n,vector<int>(m,INT_MAX));
dp[0][0] = grid[0][0];
for(int i=1;i<n;i++){
dp[i][0] = grid[i][0] + dp[i-1][0];
}
for(int i=1;i<m;i++){
dp[0][i] = grid[0][i] + dp[0][i-1];
}
for(int i=1;i<n;i++){
for(int j=1;j<m;++j){
dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]);
}
}
return dp[n-1][m-1];
}
};
1.2 题目 - 不同的路径(统计方案个数)
1)题目
http://www.lintcode.com/zh-cn/problem/unique-paths/
有一个机器人的位于一个 m × n 个网格左上角。
机器人每一时刻只能向下或者向右移动一步。机器人试图达到网格的右下角。
问有多少条不同的路径?
follow up:
中间某些格子有障碍物。
2)思路
class Solution {
public:
/*
* @param m: positive integer (1 <= m <= 100)
* @param n: positive integer (1 <= n <= 100)
* @return: An integer
*/
int uniquePaths(int m, int n) {
// write your code here
vector<vector<int>> dp(m,vector<int>(n,0));
for(int i=0;i<n;++i){
dp[0][i] = 1;
}
for(int i=0;i<m;++i){
dp[i][0] = 1;
}
for(int i=1;i<m;++i){
for(int j=1;j<n;++j){
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
};
class Solution {
public:
/*
* @param obstacleGrid: A list of lists of integers
* @return: An integer
*/
int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid) {
// write your code here
if(obstacleGrid.size()==0 || obstacleGrid[0].size() == 0){
return 0;
}
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
vector<vector<int>> dp(m,vector<int>(n,0));
for(int i=0;i<n;++i){
if(obstacleGrid[0][i]==0){
dp[0][i] = 1;
}
else{
break;
}
}
for(int i=0;i<m;++i){
if(obstacleGrid[i][0]==0){
dp[i][0] = 1;
}
else{
break;
}
}
for(int i=1;i<m;++i){
for(int j=1;j<n;++j){
if(obstacleGrid[i][j] == 1){
dp[i][j] = 0;
}
else{
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}
return dp[m-1][n-1];
}
};
1.3题目 - 爬楼梯 (统计方案个数)
1)题目
http://www.lintcode.com/zh-cn/problem/climbing-stairs/
假设你正在爬楼梯,需要n步你才能到达顶部。但每次你只能爬一步或者两步,你能有多少种不同的方法爬到楼顶部?
follow up:
一个小孩爬一个 n 层台阶的楼梯。他可以每次跳 1 步, 2 步 或者 3 步。实现一个方法来统计总共有多少种不同的方式爬到最顶层的台阶。
2)思路
dp[i] = dp[i-1] + dp[i-2] 斐波那契数列
class Solution {
pu