首先,我们要知道子序列和子串的区别,子序列可以是不连续的,而子串必须是一个连续的序列。对于最大连续子序列的和,最长递增子序列这两个问题属于一维的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问题的一点理解,本人能力有限,其中难免有不恰当之处,希望大家可以指出来,共同进步。