文章目录
1.坐标型动态规划:
1.1介绍:
1.2例题:
1.2.1:例1.
public int uniquePathsWithObstacles(int[][] A){
int m = A.length; //表示行数
if(m==0){
return 0;
}
int n =A[0].length;//表示列数
if(n==0){
return 0;
}
int [][] f = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j <n ; j++) {
if(A[i][j]==1){ //如果是障碍物的话
f[i][j]=0;
}
else{
if(i==0&&j==0){ //初始条件,如果只有一行或者只有一列
f[i][j]=1;
}
}
else{
// if(i==0) f[i][j]=f[i][j-1];
//下面的这种写法其实 和f[i][j]=f[i-1][j]+f[i][j-1];一样,让后加了上面的这种初始条件而已。
f[i][j]=0;
if(i-1>=0){
f[i][j]+=f[i-1][j];
}
if(j-1>=0){
f[i][j]+=f[i][j-1];
}
}
}
}
return f[i][j];
}
1.2.2 例2
确定状态:
子问题:
转移方程:
public class Solution{
int result =0;
void calc(int[] A,int n){
int[] f =new int[n];
for (int i = 0; i <n ; i++) {
//情况1:最长连续上升子序列就是最后一个元素。
f[i]=1;
//情况2;子序列的长度大于1.
if(i>0&&A[i-1]<A[i]){
f[i]=f[i-1]+1;
}
if(f[i]>result){
result=f[i];
}
}
}
public int longestIncreasingCotinuousSubsequence(int[] A){
int n = A.length;
if(n==0){
return 0;
}
calc(A,n); //先看顺序,
int i,j,t;
i=0;
j=n-1;
while(i<j){
t=A[i];
A[i]=A[j];
A[j]=t;
++i;
--j;
}
calc(A,n); //然后在看倒序。
return result;
}
}
2.序列型动态规划:
确定状态的时候:
子问题:注意:序列型和坐标之间的转换,
例如:数组A={0,1,2}中,前3项就表示的是0,1,2 。 i-1:就表示最后一项为2
状态转移方程:
同理可得:
初始条件和边界情况:
计算顺序:
public int minCost(int[][] cost){
//f[i][j]:是表示的前i栋房子,最后一个房子染成j这种颜色
int res;
int n=cost.length;
if(n==0){
return 0;
}
int[][] f =new int[n+1][3]; //其中3代表3种颜色。n+1: f[0]...f[n]
f[0][0]=f[0][1]=f[0][2]=0; //初始条件中没有房子的话,花费都是0;
for (int i = 0; i <=n ; i++) {
//j:是i-1房子的颜色
for (int j = 0; j <3 ; j++) { //视频中是++j。后面有机会看下我这种写法对不对
f[i][j]=Integer.MAX_VALUE; //与之前的题类似先给一个最值,
//K:是i-2房子的颜色
for (int k = 0; k <3 ; k++) { //视频中是++k。后面有机会看下我这种写法对不对
//上一个房子的颜色和这个房子的颜色不能一样。
if(j==k){
continue;
}
//这里是在找最小值,然后去替代他。
//f[i-1][k]:前i-1栋房子,且最后一个房子为K这种颜色。cost[i-1][j]:坐标上i-1栋房子的花费。始终:后者为前者的后面一个房子。
if(f[i-1][k]+cost[i-1][j]<f[i][j]){
f[i][j]=f[i-1][k]+cost[i-1][j];
}
}
}
}
res=Math.min(f[n][0],f[n][1],f[n][2]);
return res;
}
总结:
3划分型动态规划
确定状态:
子问题:
转移方程:
注意:序列型和划分性:都是前i个,最后一个是i-1.
初始条件和边界条件:
public int numDecodings(String ss){
char[] s = ss.toCharArray();
int n = s.length;
if(n==0){
return 0;
}
int[] f =new int[n+1];
f[0]=1;
for (int i = 1; i <=n ; i++) {
f[i] =0;
//最后一个数字
int t =s[i-1]-'0';
if(t>=1&&t<=9){
f[i]+=f[i-1];
}
//长度必须大于1
if(i>=2){
//倒数第2个数字。
t=(s[i-1]-'0')*10+(s[i-1]-'0');
if(t>=10&&t<=26){
f[i]+=f[i-2];
}
}
}
return f[n];
}
4.最值型动态规划
4.1例1
确定状态:
转移方程:
初始条件和边界条件:
public static int minPathSum(int[][] A){
if(A==null ||A.length==0||A[0].length==0){
return 0;
}
int m=A.length;
int n=A[0].length;
int[][] f = new int[2][n]; //这里使用的是滚动数组
int old =1,now =0;
int t1,t2;
for (int i = 0; i <m ; i++) {
old =now;
now =1-old;
for (int j = 0; j <n ; j++) {
if(i==0&&j==0){ //初始条件:只有(0,0)的时候才满足条件。
f[now][j] =A[i][j];
continue;
}
f[now][j] =A[i][j];
if(i>0){
t1=f[old][j];
}else{
t1=Integer.MAX_VALUE;
}
if(j>0){
t2=f[now][j-1];
}else{
t2=Integer.MAX_VALUE;
}
if(t1<t2){
f[i][j]+=t1;
}else{
f[now][j]+=t2;
}
}
}
return f[now][n-1];
}
4.2 例2:
其中的E:表示敌人,W:表示墙, 0:表示空格子。
确定状态:
子问题:
初始条件和边界条件
四个方向:
public int maxKilledEnemies(char[][] A){
if(A==null||A.length==0||A.length==1&&A[0].length==0){
return 0;
}
int m =A.length;
int n=A[0].length;
int[][] f =new int[m][n]; //用来更新每次上下左右的值
int[][] res =new int[m][n]; //用来保存,这个格子能炸死敌人的数目
for (int i = 0; i < m; i++) {
for (int j = 0; j <n ; j++) {
res[i][j]=0;
}
}
//计算当前格子“向上”
for (int i = 0; i <m ; i++) {
for (int j = 0; j < n; j++) {
if(A[i][j]=='W'){
f[i][j]=0;
}else{
f[i][j]=0;
if(A[i][j]='E'){
f[i][j]=1;
}
if(i>0){
f[i][j]+=f[i-1][j];
}
}
res[i][j]+=f[i][j];
}
}
//计算当前格子“向下”
for (int i = m-1; i >=0 ; i++) {
for (int j = 0; j < n; j++) {
if(A[i][j]=='W'){
f[i][j]=0;
}else{
f[i][j]=0;
if(A[i][j]='E'){
f[i][j]=1;
}
if(i+1<m){
f[i][j]+=f[i+1][j];
}
}
res[i][j]+=f[i][j];
}
}
//计算当前格子“向左”
for (int i = 0; i <m ; i++) {
for (int j = 0; j < n; j++) {
if(A[i][j]=='W'){
f[i][j]=0;
}else{
f[i][j]=0;
if(A[i][j]='E'){
f[i][j]=1;
}
if(j-1>=0){
f[i][j]+=f[i][j-1];
}
}
res[i][j]+=f[i][j];
}
}
//计算当前格子“向右”
for (int i = 0; i <m ; i++) {
for (int j =n-1; j >=0; j++) {
if(A[i][j]=='W'){
f[i][j]=0;
}else{
f[i][j]=0;
if(A[i][j]='E'){
f[i][j]=1;
}
if(j+1<n){
f[i][j]+=f[i][j+1];
}
}
res[i][j]+=f[i][j];
}
}
int result =0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if(A[i][j]=='0'){ //因为只有‘0’的地方才可以安放炸弹。
if(res[i][j]>result){
result=res[i][j];
}
}
}
}
return result;
}