前言
DP(Dynamic Programming)定义:
动态规划是分治思想的延伸,通俗一点来说就是大事化小,小事化无的艺术。在将大问题化解为小问题的分治过程中,保存对这些小问题已经处理好的结果,并供后面处理更大规模的问题时直接使用这些结果。
动态规划具备了以下三个特点:
- 把原来的问题分解成了几个相似的子问题。
- 所有的子问题都只需要解决一次。
- 储存子问题的解
动态规划的本质,是对问题状态的定义和状态转移方程的定义(状态以及状态之间的递推关系)。
动态规划问题一般从以下四个角度考虑:
- 状态定义
- 状态间的转移方程定义
- 状态的初始化
- 返回结果
状态定义的要求:定义的状态一定要形成递推关系。
一句话概括:三特点四要素两本质
适用场景:最大值/最小值, 可不可行, 是不是,方案个数;
一、字符串分割
牛客链接
状态:
子状态:前1,2,3,…,n个字符能否根据词典中的词被成功分词
F(i)
: 前i个字符能否根据词典中的词被成功分词
状态递推:
F(i): true{j < i && F(j) && substr[j+1,i]
能在词典中找到} OR false
在j小于i中,只要能找到一个F(j)为true,并且从j+1到i之间的字符能在词典中找到,则F(i)为true。
初始值:
对于初始值无法确定的,可以引入一个不代表实际意义的空状态,作为状态的起始;
空状态的值需要保证状态递推可以正确且顺利的进行,到底取什么值可以通过简单的例子进行验证,这里取F(0) = true
;
返回结果:F(n);
import java.util.*;
public class Solution {
public boolean wordBreak(String s, Set<String> dict) {
boolean[] canBreak = new boolean[s.length() + 1];
canBreak[0] = true;
for(int i = 1;i <= s.length();i++){
for(int j = 0;j < i;j++){
if(canBreak[j] && dict.contains(s.substring(j,i))){
canBreak[i] = true;
break;
}
}
}
return canBreak[s.length()];
}
}
二、三角矩阵的最小路径和
状态:
子状态:从(n,n),(n,n-1),...(1,0),(1,1),(0,0)
到最后一行的最短路径和;
F(i,j)
: 从(i,j)到最后一行的最短路径和;
状态递推:F(i,j) = min( F(i+1, j), F(i+1, j+1)) + triangle[i][j]
;
初始值:F(n-1,0) = triangle[n-1][0], F(n-1,1) = triangle[n-1][1],..., F(n-1,n-1) = triangle[n-1][n-1]
;
返回结果:F(0, 0)
;
自底向上的方法,确定最后一行的最小值,然后从倒数第二行开始。
import java.util.*;
public class Solution {
public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
if(triangle.isEmpty()){
return 0;
}
//初始化
ArrayList<ArrayList<Integer>> minPathSum = new ArrayList<>(triangle);
int row = minPathSum.size();
//从倒数第二行开始
for(int i = row - 2;i >=0;i--){
for(int j = 0;j <= i;j++){
// F(i,j) = min( F(i+1, j), F(i+1, j+1)) + triangle[i][j]
int curSum = Math.min(triangle.get(i+1).get(j),triangle.get(i+1).get(j + 1)) + triangle.get(i).get(j);
minPathSum.get(i).set(j,curSum);
}
}
return minPathSum.get(0).get(0);
}
}
三、路径总数
牛客链接
状态:
子状态:从(0,0)
到达(1,0),(1,1),(2,1),...(m-1,n-1)
的路径数;
F(i,j)
: 从(0,0)
到达F(i,j)
的路径数
状态递推:F(i,j) = F(i-1,j) + F(i,j-1)
初始化:
特殊情况:第0行和第0列:F(0,i) = 1,F(i,0) = 1
;
返回结果:F(m-1,n-1)
;
import java.util.*;
public class Solution {
/**
*
* @param m int整型
* @param n int整型
* @return int整型
*/
public int uniquePaths (int m, int n) {
int[][] dp = new int[m][n];
for(int i = 0;i