zoukankan      html  css  js  c++  java
  • 动态规划

    有数组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[n][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[n][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[n];
    		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[n][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[n][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];
        }
    }
    

      

  • 相关阅读:
    Nginx开发从入门到精通
    Nginx配置文件(nginx.conf)配置详解
    转贝叶斯推断及其互联网应用(一):定理简介
    Vim 使用入门快捷键
    从贝叶斯定理说开去
    转特征值和特征向量
    第四章 特征值与特征向量
    numpy基础入门
    python range函数与numpy arange函数
    转悠望南山 Python闲谈(二)聊聊最小二乘法以及leastsq函数
  • 原文地址:https://www.cnblogs.com/lxk2010012997/p/5545026.html
Copyright © 2011-2022 走看看