动态规划
1找零
有数组penny,penny中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim(小于等于1000)代表要找的钱数,求换钱有多少种方法。
给定数组penny及它的大小(小于等于50),同时给定一个整数aim,请返回有多少种方法可以凑成aim。
[1,2,4],3,3
返回:2
import java.util.*; public class Exchange { public int countWays(int[] penny, int n, int aim) { int[] aims = new int[1000]; aims[0]=1; for(int i =0; i<n; ++i){ for(int j = penny[i]; j<=aim;++j){ aims[j]+=aims[j-penny[i]]; } } return aims[aim]; } }
import java.util.*; public class Exchange { public int countWays(int[] penny, int n, int aim) { if (penny == null || penny.length == 0 || aim < 0) { return 0; } int[][] dp = new int[penny.length][aim + 1]; for (int i = 0; i < n; i++) { dp[i][0] = 1; } for(int i=0;i<aim+1;i++){ if(i%penny[0]==0) dp[0][i]=1; } for (int i = 1; i < penny.length; i++) { for (int j = 1; j <= aim; j++) { if(penny[i]>j) dp[i][j]=dp[i-1][j]; else dp[i][j]=dp[i-1][j]+dp[i][j-penny[i]]; } } return dp[n-1][aim]; } }
2台阶问题
有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法。为了防止溢出,请将结果Mod 1000000007
给定一个正整数int n,请返回一个数,代表上楼的方式数。保证n小于等于100000。
1
返回:1
import java.util.*; public class GoUpstairs { public int countWays(int n) { // write code here int current = 0; int prev = 0; for (int i = 1; i <= n; i++) { if (i == 1) { current = 1; } else if(i == 2){ prev = current; current = 2; } else { int temp = prev; prev = current; current = (temp + prev) % 1000000007; } } return current; } }
import java.util.*; public class GoUpstairs { public int countWays(int n) { // write code here int f1=1; int f2=2; if (n==1){ return f1; } for(int i=3;i<=n;i++){ int temp=(f1+f2)%1000000007; f1=f2; f2=temp; } return f2; } }
3矩阵最小路径
有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。
给定一个矩阵map及它的行数n和列数m,请返回最小路径和。保证行列数均小于等于100.
[[1,2,3],[1,1,1]],2,3
返回:4
import java.util.*; public class MinimumPath { public int getMin(int[][] map, int n, int m) { // write code here int[][] dp=new int[n][m]; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ dp[i][j]=0; } } dp[0][0]=map[0][0]; for(int i=1;i<n;i++){ dp[i][0]+=map[i][0]+dp[i-1][0]; } for(int i=1;i<m;i++){ dp[0][i]+=map[0][i]+dp[0][i-1]; } for(int i=1;i<n;i++){ for(int j=1;j<m;j++){ dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+map[i][j]; } } return dp[n-1][m-1]; } }
4LIS
这是一个经典的LIS(即最长上升子序列)问题,请设计一个尽量优的解法求出序列的最长上升子序列的长度。
给定一个序列A及它的长度n(长度小于等于500),请返回LIS的长度。
[1,4,2,5,3],5
返回:3
import java.util.*; public class LongestIncreasingSubsequence { public int getLIS(int[] A, int n) { // write code here if (A == null) return 0; int[] dp = new int[n]; dp[0] = 1; int top = 0; for (int i = 1; i < n; ++i) { int max = 0; for (int j = i - 1; j >= 0; --j) { if (max < dp[j] && A[j] < A[i]) max = dp[j]; } dp[i] = max + 1; if (top < dp[i]) top = dp[i]; } return top; } }
import java.util.*; public class LongestIncreasingSubsequence { public int getLIS(int[] A, int n) { int[] dp = new int[n]; dp[0] = 1; int top = 0; for (int i = 1; i < n; ++i) { int max = 0; for (int j = i - 1; j >= 0; --j) { if (A[j] < A[i]) max = Math.max(dp[j],max); } dp[i] = max + 1; if (top < dp[i]) top = dp[i]; } return top; } }
import java.util.*; public class LongestIncreasingSubsequence { public int getLIS(int[] A, int n) { int[] dp = new int[n]; dp[0] = 1; int top = 0; for (int i = 1; i < n; ++i) { int max = 0; for (int j = i - 1; j >= 0; --j) { if (max < dp[j] && A[j] < A[i]) max = dp[j]; } dp[i] = max + 1; if (top < dp[i]) top = dp[i]; } return top; } }
5LCS
给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。
给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300。
"1A2C3D4B56",10,"B1D23CA45B6A",12
返回:6
import java.util.*; public class LCS { public int findLCS(String A, int n, String B, int m) { char[] a = A.toCharArray(); char[] b = B.toCharArray(); int[][] dp = new int[n+1][m+1]; // 为了避免越界,都从数组下标 1 开始 for (int i = 1; i <= n; i++){ for (int j = 1; j <= m; j++){ if (a[i-1] == b[j-1]){ dp[i][j] = dp[i-1][j-1] + 1; } else{ dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); } } } return dp[n][m]; } }
601背包
一个背包有一定的承重cap,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。
给定物品的重量w价值v及物品数n和承重cap。请返回最大总价值。
[1,2,3],[1,2,3],3,6
返回:6
import java.util.*; public class Backpack { public int maxValue(int[] w, int[] v, int n, int cap) { // dp[x][y]表示物品数量为x,重量不超过y时背包中的总价值 //两种情况:1.将x物品不加入到背包中,那么前x-1件物品的总重量不应该超过y。dp[x][y] = dp[x-1][y] //2.将x物品加入到背包中,那么前x-1前物品的总重量不应该超过y-w(x),因此dp[x][y] = dp[x-1][y-w(x)]+v(x); int[] dp = new int[cap+1]; for(int i=0;i<n;i++){//控制物品的数量 for(int j=cap;j>=w[i];j--){//空背包中不能超重 dp[j] = dp[j]>=dp[j-w[i]]+v[i]?dp[j]:dp[j-w[i]]+v[i];//选取j加入书包与j不加入书包的较大值 } } return dp[cap];//返回数组的最后一位即是最大总价值 } }
import java.util.*; public class Backpack { public int maxValue(int[] w, int[] v, int n, int cap) { int[][] bag = new int[w.length][cap+1]; for (int i = 0; i <= cap; i++) { if (i >= w[0]) { bag[0][i] = v[0]; } } for (int i = 1; i < w.length; i++) { int b = 0; for (int j = 1; j <= cap; j++) { int a = bag[i-1][j]; if(j - w[i] >= 0){ b = 0; b = bag[i-1][j - w[i]] + v[i]; } bag[i][j] = a > b? a : b; } } return bag[w.length-1][cap]; } }
7最优编辑
对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。
给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。保证两串长度均小于等于300,且三种代价值均小于等于100。
"abc",3,"adc",3,5,3,100
返回:8
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 if((A==null&&B==null)||(m==0&&n==0))return 0; int[] dp=new int[m+1]; char[] a=A.toCharArray(); char[] b=B.toCharArray(); for(int i=0;i<=m;i++) { dp[i]=i*c0; } for(int i=1;i<=n;i++) { int pre=dp[0]; dp[0]=c1*i; for(int j=1;j<=m;j++) { int cur=0; if(a[i-1]==b[j-1]) { cur=pre; }else{ cur=pre+c2; } pre=dp[j]; dp[j]=Math.min(dp[j]+c1,Math.min(cur,dp[j-1]+c0)); } } return dp[m]; } }

浙公网安备 33010602011771号