题目:长度为n的num数组,求其最长递增子序列
思考:
-
该数组中元素所构成的所有递增子序列可以穷举为以所有元素结尾的递增子序列。
-
则求最长递增子序列的长度转化为求以各个元素结尾的递增子序列的最长的长度
-
以下标i结尾的最长递增子序列长度与以下标为i-1结尾的最长递增子序列长度有关-。
动态规划求解思路 -
自底向上穷举
/*
num[]={10,9,2,5,3,7,101,18}
1:以10结尾的序列,其最长递增子序列长度为1;
2、以9结尾的序列,其最长递增子序长度为1;
3、以2结尾的序列,其最长递增子序列长度为1;
4、以5结尾的序列,其最长递增子序列长度为2:
因为2<5, 所以在以5结尾的序列中,以2结尾的序列可以添加到以5结尾的序列前,又以2结尾的序列,最长递增子序列长度为1,则以5结尾的序列最长递增子序列长度为 1+1=2;
5、以3结尾的序列,其最长递增子序列长度为2: 1+1=2;
6、以7结尾的序列,其最长递增子序列长度为3:
因为 2<7, 又以2结尾的最长递增子序列长度为1,故将2添加入当前子序列,其长度为 1+1=2; 5<7,又以5结尾的最长递增子序列长度为2, 则将5加入当前子序列, 其长度为2+1=3; 同理得到将3加入之后最长递增子序列长度为3
......
同理可得各自结尾的最长递增子序列
*/
-
确定边界(初始化):
对于数组中任意一个元素结尾的子序列其长度至少为1。 -
找规律
假定dp[i]用来表示以i结尾的最长递增子序列的长度,则dp[i]=max(dp[j])+1,(j>=0&&j<i&&num[j]<num[i])
【以i结尾的所有递增子序列的长度等于i之前,比num[i]小的值结尾的的子序列长度+1,则以i结尾的最长递增子序列长度为其中长度最长的值】 -
状态转移方程
dp[i]=max(dp[j])+1, for all j, 0<=j<i&&num[j]<num[i]
dp[i]=1 for all j, 0<=j<i&&num[j]>num[i]
- 代码实现
//num[]={10,9,2,5,3,7,101,18}
public int lengthOfLIS(int[] num){
//创建一个dp[]数组,用来存储以各个元素结尾的最长递增子序列长度
int[]dp=new int[num.lenght];
int maxlenght=0;
//计算以各个元素结尾的最长递增子序列长度
for(int i=0;i<num.lenght;i++){
//以i结尾的所有子序列中包含自身,且其长度为1
dp[i]=1;
for(int j=0;j<i;j++){
//以i结尾的其他子序列长度计算
if(num[j]<num[i]){
dp[i]=Math.max(dp[j]+1,dp[i]);
}
}
//最大的dp[i]即为最长递增子序列长度
maxlenght=Math.max(dp[i],naxlength);
}
return maxlength;
}