动态规划(二)

坐标型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];
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lcctt

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值