问题描述
在一个给定的数值序列中,找到一个子序列,使得这个子序列元素的数值依次递增,并且这个子序列的长度尽可能地大。最长递增子序列中的元素在原序列中不一定是连续的。
动态规划的逻辑,借助高中数学的归纳法,我们先假设这个结论在 k<n 时成立,然后根据这个假设,想办法推导证明出 k=n 的时候此结论也成立。如果能够证明出来,那么就说明这个结论对于 k 等于任何数都成立。
步骤
定义数组array
定义数组dp,dp[i] 表示以 array[i] 这个数结尾的最长递增子序列的长度。dp[i] 初始值为 1,因为以 array[i] 结尾的最长递增子序列起码要包含它自己。
假设我们已经知道了 dp[0…i] 的所有结果,我们如何通过这些已知结果推出 dp[i+1] 呢?
动态规划的核心:array[i+1] = k,既然是递增子序列,我们只要找到前面那些结尾比k小的子序列,然后把 k 接到最后,就可以形成一个新的递增子序列,而且这个新的子序列长度加一
比如数组:1,4,3,4,2。
对应的
dp[0]=1;
dp[1]=2;
dp[2]=2;
dp[3]=3;
dp[4]=2
如果在后面增加一个数3。则数组变为1,4,3,4,2,3;那么dp[5]怎么算呢?找到比3小的数字对应的dp[i]最大值(也就是最长),然后+1,就是dp[5]的值。也就是array[4]=2的值小于3,且dp[4]=2最长。
package com.algorithm;
import java.util.Arrays;
/**
* long increasing subseq
*/
public class LIS {
public static void main(String[] args) {
Integer[] array = new Integer[]{1,4,3,4,2,3};
int[] dp = new int[array.length];
Arrays.fill(dp,1); //初始化为1
for(int i = 0; i<array.length;i++) {
for(int j = 0; j<i;j++) {
if(array[j] < array[i]) {
//找到了当前的值array[i]比array[0..j]小
dp[i] = Math.max(dp[i],dp[j]+1);//取dp值最大,也就是最长的序列
}
}
}
//输出最长子序列的长度
int res = 0;
for (int i = 0; i < dp.length; i++) {
res = Math.max(res, dp[i]);
}
System.out.println("long increasing subseq:"+res);
}
}