坐标型DP
序列型DP
划分型DP
1.坐标型DP
题目:m行n列网格,从左上角(0,0)位置开始走,有些地方是障碍,不可以走,问有多少种方式走到右下角
DP
/*
思路:
1.f[0][0] = 0;
2.if(i==0 || j==0){
f[i][j] = 1;
}
3.如果第(i,j)个格子有障碍,则f[i][j]=0
*/
public int solution(int[][] arr){
int m = arr.length;
if(m == 0){
return -1;
}
int n = arr[0].length;
if(n == 0){
return -1;
}
int[][] f = new int[m][n];
f[0][0]=1;
for(int i =0;i<m;++i){
for(int j = 0;j<n;++j){
//当给定数组的元素值是1时,表明当前格子是障碍格子
if(arr[i][j] == 1){
f[i][j] = 0;
}else{
if(i == 0 || j == 0 ){
//边界
f[i][j] = 1;
}else{
f[i][j] = f[i][j-1]+f[i-1][j];
}
}
}
}
return f[m-1][n-1];
}
2.序列型DP
题目:有一排N栋的房子,每栋房子要涂成3中颜色中的一种:红、蓝、绿
任何两栋相邻的房子不能涂成相同的颜色
第i栋房子染成红色、蓝色、绿色所需要的费用分别是cost[i][0],cost[i][1]和cost[i][2]
怎么才能花费最少的费用来涂这些房子
这类问题如果要知道第n栋房子的最小花费,则需要知道第n-1栋房子的最小花费,而且需要知道n-1栋房子涂成了什么颜色
所以需要开一个二维数组
int[][] f = new int[n][2];
/*
其中:
f[i][0]:代表当前房子涂成红色的最小花费
f[i][1]:代表当前房子涂成蓝色的最小花费
f[i][2]:代表当前房子涂成绿色的最小花费
*/
//这里第i栋房子的花费在数组中展示的是cost[i-1][...],因为cost的起始索引是0
f[i][0] = Math.min(f[i-1][1]+cost[i-1][0],f[i-1][2]+cost[i-1][0]);
f[i][1] = Math.min(f[i-1][0]+cost[i-1][0],f[i-1][2]+cost[i-1][0]);
f[i][2] = Math.min(f[i-1][1]+cost[i-1][0],f[i-1][0]+cost[i-1][0]);
//初始条件,从没有房子开始
f[0][0] = f[0][1] = f[0][2]=0
完整代码:
public int minCost(int[][] costs){
int n = costs.length;
if(n == 0){
return 0;
}
//这里由于第一个房子是假设的,即从没有房子开始算起,所以开的数组的第一维度的大小是n+1
int[][] f = new int[n+1][3];
f[0][0] = f[0][1] = f[0][2] = 0
for(int i = 0; i<n+1; ++i){
for(int j = 0;j<3;++j){
f[i][j] = Integer.MAX_VALUE;
for(int k = 0; k<3;++k){
/*
每次计算第i个房子时,由于第i个房子只可能取两种颜色,所以需要在加一层循环
这里的k是第i-1栋房子涂成的颜色,j是第i栋房子涂成的颜色
比如在计算第m栋房子的时候
如果要填充f[m][0]元素,需要比较第m-1栋房子是蓝色或者绿色的情况下花费的最小值
也就是f[i-1][k] + cost[i-1][j] < f[i][j]
所以每填充一组一维元素,比如f[2][0],f[2][1],f[2][2]
共需要比较六次
然后按照顺序计算下去即可
*/
if(k == j){
continue;
}
if(f[i-1][k] + cost[i-1][j] < f[i][j]){
f[i][j] = f[i-1][k] + cost[i-1][j];
}
}
}
}
return Math.min(f[n][0],Math.min(f[n][1],f[n][2]));
}
3.划分型动态规划
问题:一个字符串由A、B。。。。。Z构成
加密方式:A--->1,B--->2...Z--->26
然后给定一个加密后的串,怎么确定这个串可以解密成多少个字符创
例如:
12:可以解析成AB,还可以解析成L
代码:
/*
思路:如果想知道前n个字符的解密种数,则需要知道第n-1和n-2个字符的解密种数
因为要么第n个字符自己被解密,要么第n个字符和第n-1个字符合起来被解密,也就是要对解密后的最后一个字母进行划分
所以f[n] = f[n-1]+f[n-2],但是是有条件的,必须小于26
*/
public int solution(String ss){
char[] s = ss.toCharArray();
int length = s.length;
if(length == 0){
return 0;
}
int[] f = new int[n];
for(int i = 0;i<length;i++){
if(i == 0){
f[i] = 1;
}
//将s数组中的char转换成为数字
//个位
int n1 = s[i] -'0';
//十位
int n2 = s[i-1]-'0' ;
if(i == 1){
if(n2 * 10+n1 > 26){
f[i] = 1;
}else{
f[i] = 2;
}
}
if(n2 * 10+n1 > 26){
f[i] = f[i-1]
}else{
f[]= f[-1]+f[i-2];
}
}
return f[n-1];
}