动态规划几个典型题总结

这是典型的三道动态规划,在笔试当中,有可能会被举一反三地考。

1、求一个数组最大连续子数组之和。

      示例:int[] nums = {2,1,3,6,-10,5};  最大连续子数组是2,1,3,6,所以输出12。

2、求一个数组的最长递增子序列。

      示例:int[] nums = {2,1,3,6,-10,5};    最长递增子序列是1,3,6,所以输出3。

3、求两个字符串的最大公共子串。

      示例:String str1 = "bcfde";      String str2 = "abcef";    输出bc。

4、求两个字符串的最大公共子序列的个数。

      示例:String str1 = "bcfde";      String str2 = "abcef";    最大公共子序列是bcf,输出3。


第一个问题:

最经典!连续,和最大。这两个重点,用两个变量标记,一个是localmax = Math.max(nums[i], nums[i]+localmax); 什么意思呢?当前值nums[i]与nums[i]+localmax取大,比如,上一步算出的localmax为-10,现在nums[i] = 5,很明显,就选择5作为localmax,前面所有的数将不再最终候选子数组中。另一个是max = Math.max(max, localmax),这很明显了,你算出来了localmax,自然要和上一步计算出的max作比较,取大值。

第二个问题:

问题稍复杂。dp[i]表示以下标i结尾的子数组中最长递增子序列的长度,状态转移 方程为:dp[i] = Math.max(dp[j]+1, dp[i]),这里的j为1<=j<i;

第三个问题:

序贯决策,高大上!用一个二维矩阵记录结果。举例子来说


需要记录的是,max = 2, maxindex = 1; 返回的是str1.subString(maxindex+1-max, maxindex+1);

第三个问题:

在上一个问题基础上有了拓展,不需要连续,只要有相同即可,同样用二维矩阵记录结果,


最后输出3即可。


代码:

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		String str1 = "bcfde";
		String str2 = "abcef";
		System.out.println("最大公共子串:"+getLCString(str1, str2));
		System.out.println("最长公共子序列个数:"+LCS(str1, str2));
		
		int[] nums = {2,1,3,6,-10,5};
		System.out.println("一个数组的最长递增子序列:"+getLIS(nums));
		System.out.println("一个数组的最大连续子数组之和:"+getMaxSubArr(nums));
	}

	/**
	 * 一个数组的最长递增子序列
	 * @param nums
	 * @return
	 */
	public static int getLIS(int[] nums){
		if(nums == null || nums.length == 0)
			return 0;
		int max = 1;
		int[] dp = new int[nums.length];
		for(int i=0; i<nums.length; i++){
			dp[i] = 1;
			for(int j=0; j<i; j++){
				if(nums[j] < nums[i]){
					dp[i] = Math.max(dp[i], dp[j]+1);
					max = Math.max(max, dp[i]);
				}
			}
		}
		return max;
	}
	
	/**
	 * 两个字符串的最大公共子串
	 * @param str1
	 * @param str2
	 * @return
	 */
	public static String getLCString(String str1, String str2) {
		int len1 = str1.length();
		int len2 = str2.length();
		if(str1 == null || str2 == null || len1 == 0 || len2 == 0){
			return null;
		}
		int maxlen = 0;  
		int endindex = 0;
		int[][] dp = new int[len1][len2];
		for(int i=0; i<len1; i++){
			for(int j=0; j<len2; j++){
				if(i == 0 || j == 0) {
					dp[i][j] = str1.charAt(i) == str2.charAt(j) ? 1 : 0;
				}else{
					dp[i][j] = str1.charAt(i) == str2.charAt(j) ? dp[i-1][j-1]+1 : 0;
				}
				if(maxlen < dp[i][j]){
					maxlen = dp[i][j];
					endindex = i;
				}
			}
		}
		return str1.substring(endindex+1-maxlen, endindex+1);
	}
	
	/**
	 * 两个字符串的公共子序列
	 * @param str1
	 * @param str2
	 * @return
	 */
	public static int LCS(String str1, String str2){
		int len1 = str1.length();
		int len2 = str2.length();
		int max = 0;
		
		int[][] dp = new int[len2+1][len1+1];
		for(int i=0; i<=len2; i++){
			dp[i][0] = 0;
		}
		for(int j=0;  j<=len1; j++){
			dp[0][j] = 0;
		}
		for(int i=1; i<=len1; i++){
			for(int j=1; j<=len2; j++){
				if(str1.charAt(i-1) == str2.charAt(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]);
				}
				
				if(max < dp[i][j]){
					max = dp[i][j];
				}
			}
		}
		return max;
	}
	
	public static void print(int[][] dp, String X, String Y, int i, int  j){
		if(i == 0 || j == 0){
			return;
		}
		
		if(X.charAt(i-1) == Y.charAt(j-1)){
			System.out.print(X.charAt(i-1));
			print(dp, X, Y, i-1, j-1);
		}else if(dp[i-1][j] >= dp[i][j]){
			print(dp, X, Y, i-1, j);
		}else{
			print(dp, X, Y, i, j-1);
		}
	}
	
	/**
	 * 一个数组最大连续子数组之和
	 * @param nums
	 * @return
	 */
	public static int getMaxSubArr(int[] nums){
		int localmax = nums[0];
		int max = nums[0];
		for(int i=1;  i<nums.length; i++){
			localmax = Math.max(nums[i], localmax+nums[i]);
			max = Math.max(max, localmax);
		}
		return max;
	}
	
}
结果:




发布了120 篇原创文章 · 获赞 25 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/yearningseeker/article/details/52503834