您的位置:首页 > 其它

动态规划

2016-06-01 09:50 423 查看
有数组penny,penny中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim(小于等于1000)代表要找的钱数,求换钱有多少种方法。

给定数组penny及它的大小(小于等于50),同时给定一个整数aim,请返回有多少种方法可以凑成aim。

测试样例:
[1,2,4],3,3

返回:2
思路:这里dp[i][j]表示用前i种货币得到面值j的方法数。


import java.util.*;

public class Exchange {
public int countWays(int[] penny, int n, int aim) {
// write code here
int[][] dp = new int
[aim+1];
for(int i = 0;i < n; i++)
dp[i][0] = 1;
for(int i = 1;i <= aim; i++){
if(i%penny[0]==0)
dp[0][i] = 1;
else
dp[0][i] = 0;
}
for(int i = 1;i < n; i++){
for(int j = 1;j <= aim; j++){
int count = 0;
int k = 0;
while(j-k*penny[i]>=0){
count += dp[i-1][j-k*penny[i]];
k++;
}
dp[i][j] = count;
}
}

return dp[n-1][aim];
}
}


有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法。为了防止溢出,请将结果Mod 1000000007

给定一个正整数int n,请返回一个数,代表上楼的方式数。保证n小于等于100000。

测试样例:
1

返回:1


public class GoUpstairs {
public int countWays(int n) {
int f1 = 1;
int f2 = 2;
for(int i = 3; i <= n; ++i){
int temp = (f1 + f2)%1000000007;
f1 = f2;
f2 = temp;
}
return f2 ;
}
}


  

有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。

给定一个矩阵map及它的行数n和列数m,请返回最小路径和。保证行列数均小于等于100.

测试样例:
[[1,2,3],[1,1,1]],2,3

返回:4
思路:这个地方dp[i][j]表示从(0,0)到(i,j)的最小路径和。


public static int getMin(int[][] map, int n, int m) {
// write code here
int[][] dp = new int
[m];
int sum = 0;
for(int i = 0;i < m; i++){
dp[0][i] = sum+map[0][i];
sum = dp[0][i];

}

sum = 0;
for(int i = 0;i < n; i++){
dp[i][0] = sum+map[i][0];
sum = dp[i][0];
}

for(int i = 1;i < n; i++)
for(int j = 1;j < m; j++)
dp[i][j] = Math.min(dp[i-1][j]+map[i][j], dp[i][j-1]+map[i][j]);
return dp[n-1][m-1];
}


  

这是一个经典的LIS(即最长上升子序列)问题,请设计一个尽量优的解法求出序列的最长上升子序列的长度。

给定一个序列A及它的长度n(长度小于等于500),请返回LIS的长度。

测试样例:
[1,4,2,5,3],5

返回:3
思路:这个地方dp[i]表示以第i个数字结尾的最长递增子序列长度。


public static int getLIS(int[] A, int n) {
// write code here
int[] dp = new int
;
dp[0] = 1;
for(int i = 1;i < n; i++)
dp[i] = 0;
int result = 0;
for(int i = 1;i < n; i++){
int max = 0;
for(int j = i-1;j >= 0; j--)
if(A[j]<A[i]&&dp[j]>max)
max = dp[j];
dp[i] = max+1;
if(dp[i]>result)
result = dp[i];
}

return result;
}


  

一个背包有一定的承重cap,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。

给定物品的重量w价值v及物品数n和承重cap。请返回最大总价值。

测试样例:
[1,2,3],[1,2,3],3,6

返回:6
思路:这个地方dp[i][j]表示前i个物品在容量为j时所能达到的最大价值。


import java.util.*;

public class Backpack {
public int maxValue(int[] w, int[] v, int n, int cap) {
// write code here
int m = 0;
for(int i = 0;i < n; i++)
m += w[i];
//System.out.println(m);
int[][] dp = new int
[m+1];
for(int i = 0;i < n; i++)
dp[i][0] = 0;

for(int i = 0;i <= m; i++)
if(i>=w[0])
dp[0][i] = v[0];

for(int i = 1;i < n; i++){
for(int j = 1;j <= m; j++){
if(j-w[i]>=0)
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]);
else
dp[i][j] = dp[i-1][j];
//System.out.print(dp[i][j]+" ");
}
//System.out.println();
}

if(cap>m)
return dp[n-1][m];
else
return dp[n-1][cap];
}
}


  

对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。

给定两个字符串AB,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。保证两串长度均小于等于300,且三种代价值均小于等于100。

测试样例:
"abc",3,"adc",3,5,3,100

返回:8
思路:dp[i][j]表示把A[0...i-1]字符串转换为B[0...j-1]的最小代价


import java.util.*;

public class MinCost {
public int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
// write code here
int[][] dp = new int[A.length()+1][B.length()+1];
for(int i = 0;i <= B.length(); i++)
dp[0][i] = i*c0;
for(int i = 1;i <= A.length(); i++)
dp[i][0] = i*c1;
for(int i = 1;i <= A.length(); i++)
for(int j = 1;j <= B.length(); j++){
int result = dp[i-1][j]+c1;			//删除
int result2 = dp[i][j-1]+c0;		     //添加
int result3 = 0;
if(A.charAt(i-1)!=B.charAt(j-1))         //替换 
result3 = dp[i-1][j-1]+c2;
else
result3 = dp[i-1][j-1];
int min = result<result2?result:result2;
min = min<result3?min:result3;
dp[i][j] = min;
}
//		for(int i = 0;i <= A.length(); i++){
//			for(int j = 0;j <= B.length(); j++)
//				System.out.print(dp[i][j]+" ");
//			System.out.println();
//		}
return dp[A.length()][B.length()];
}
}


  

给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。

给定两个字符串AB,同时给定两个串的长度nm,请返回最长公共子序列的长度。保证两串长度均小于等于300。

测试样例:
"1A2C3D4B56",10,"B1D23CA45B6A",12

返回:6
思路:dp[i][j]代表A[0...i]和B[0...j]的最长子序列长度。


import java.util.*;

public class LCS {
public int findLCS(String A, int n, String B, int m) {
// write code here
int[][] dp = new int
[m];
boolean flag = false;
for(int i = 0;i < m; i++)
if(flag){
dp[0][i] = 1;
}else if(A.charAt(0)==B.charAt(i)){
flag = true;
dp[0][i] = 1;
}
flag = false;
for(int j = 0;j < n; j++)
if(flag){
dp[j][0] = 1;
}else if(A.charAt(j)==B.charAt(0)){
flag = true;
dp[j][0] = 1;
}

for(int i = 1;i < n; i++)
for(int j = 1;j < m; j++){
int result = dp[i-1][j];
int result2 = dp[i][j-1];
int result3 = 0;
if(A.charAt(i)==B.charAt(j))
result3 = dp[i-1][j-1]+1;
int max = result>result2?result:result2;
max = max>result3?max:result3;
dp[i][j] = max;
}
//    	for(int i = 0;i < n; i++){
//    		for(int j = 0;j < m; j++)
//    			System.out.print(dp[i][j]+" ");
//    		System.out.println();
//    	}
return dp[n-1][m-1];
}
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: