动态规划经典问题小结

近期重新复习了一下动态规划(DP),整理了一些经典的动态规划问题,接下来我就给大家介绍一下,其中包括最大连续子序列的和,最长递增子序列,最长公共子序列,最长公共子串。(如果不清楚DP的概念可以查阅网上的资料,我就不重复了。。。)

首先,我们要知道子序列和子串的区别,子序列可以是不连续的,而子串必须是一个连续的序列。对于最大连续子序列的和,最长递增子序列这两个问题属于一维的DP,最长公共子序列,最长公共子串属于二维的DP问题。

1. 最大连续子序列的和
对于这道题,我们可以理解成找出一个子串,使它的和最大。 解决这个问题我们可以设定两个变量current和global,current保存当前的最大值,global保存全局的最大值。假设给定了一个数组nums[],从中找出一个子串,使子串的和最大(如果是字符串基本原理也一样)。代码如下:
public int maxSubArray(int[] nums) {
        if(nums == null || nums.length == 0)
            return 0;
        int cur = nums[0];
        int global = nums[0];
        for(int i = 1; i < nums.length; i++) {
            cur = Math.max(nums[i], cur + nums[i]);
            global = Math.max(global, cur);
        }
        return global;
    }


2. 最长递增子序列(LIS)
给定一个数组,找出最长的递增序列。例如给定{10, 9, 2, 5, 3, 7, 101},{2,3,7,101}是最长的子序列,此时return 4。这道题也是一个一维的DP问题。假设给我们一个数组nums[],首先我们设定一个辅助数组result[],长度为nums.length,初始化所有的值为1,代表长度最小为1。并且我们设定一个全局的变量max始终记录最大的长度。首先我们从数组的第二个元素开始,依次与它前面的元素比较。如果当前元素nums[i] > nums[j](i > j),此时的递推公式为result[i] = max(result[i], result[j] + 1), 并且比较result[i]与max的值,如果result[i] > max, 令max = result[i]. 代码如下:
public int lengthOfLIS(int[] nums) {
        if(nums == null || nums.length == 0) return 0;
        int[] result = new int[nums.length];
        Arrays.fill(result, 1);
        int max = 1;
        for (int i = 1; i < nums.length; i++) {
            for(int j = 0; j < i; j++){
             //如果是非递减序列 if(nums[i] >= nums[j])   
                    if(nums[i] > nums[j]) {
                           result[i] = Math.max(result[i], result[j] + 1);
                    if(result[i] > max)
                           max = result[i];
                }
            }
        }
        return max;
    }


3. 最长公共子序列 和最长公共子串
最长公共子序列和最长公共子串问题都是一个二维的DP问题,给定两个字符串s, t, 从两个字符串中找到最长的一个公共子序列或子串。这两个问题都很大的相似之处,因为我们通过对比,一起解决这两个问题。假设字符串s="acdb", t ="abdc"。第一次比较s0 == t0, 此时result[i][j] = 1, 接下来我们需要比较s1 是否等于t1,此时s1 != t1, 如果是公共子序列,我们需要保存一个最大值,result[i][j] = Math.max(result[i-1][j], result[i][j-1]), 因为此时的子序列并没有中断,如果后面还可以继续匹配,长度要在此基础上增加; 如果是公共子串, 我们只需要维护一个全局的变量,记录每次匹配是的最大值,因为子串必须是连续的,如果当前比较不相等,我们仅需要得到以前的可以匹配的子串的最大长度即可。代码如下

最大公共子序列:
public static int lonestCommenSubsquence(String s, String t) {
		int[][] result = new int[s.length()+1][t.length()+1];
		for (int i = 1; i <= s.length(); i ++)
			for (int j = 1; j <= t.length(); j ++) {
				if(s.charAt(i - 1) == t.charAt(j - 1)){
					result[i][j] = result[i - 1][j - 1] + 1;
				}else{
					result[i][j] = Math.max(result[i-1][j], result[i][j-1]);
				}
				
			}
		return result[s.length()][t.length()];
}


最大公共子串:
public static int longestCommenSubstring(String s, String t) {
		int m = s.length();
		int n = t.length();
		int[][] result = new int[m+1][n+1];
		int max = 0;
		for(int i = 1; i <= m; i++)
			for(int j = 1; j <= n; j++) {
				if(s.charAt(i - 1) == t.charAt(j - 1)){
					result[i][j] = result[i - 1][j - 1] + 1;
				if(result[i][j] > max)
					max = result[i][j];
				}
		}
		return max;
}


以上都是DP最基本的问题,也是我自己对DP问题的一点理解,本人能力有限,其中难免有不恰当之处,希望大家可以指出来,共同进步。

猜你喜欢

转载自kickcode.iteye.com/blog/2260196