动态规划

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"都是最长公共子序列。

给定两个字符串AB,同时给定两个串的长度nm,请返回最长公共子序列的长度。保证两串长度均小于等于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串所需要的最少代价。

给定两个字符串AB,及它们的长度和三种操作代价,请返回将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];
    }
}


posted @ 2017-05-21 12:53  临江仙zhe  阅读(129)  评论(0)    收藏  举报