求最长上升子序列
笔者在湖大参加WPS笔试时曾碰这么一道问题,当时没有想出好的办法,回学校后赶紧查了资料,现在我用自己的语言描述一下。
问题描述
一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
输入:任意长度的数组
输出:该数组中最长子序列的长度
案例:
输入:[1, 7, 3, 5, 9, 4, 8]
输出:[1, 3, 5, 8]
解题思路
有经验的同学一定可以看出来,这就是一道动态规划的题目,那么我们就只需要找出它的子问题。这道题的子问题我们可以设为“求以ak(k=1, 2, 3…N)为终点的最长上升子序列的长度“,注意,这里的子问题我们不是设为”求到ak(k=1, 2, 3…N)为止的a1,a2…ak之间数组的最长上升子序列的长度“。
转移方程也就随之而出了
①MaxLen (1) = 1 //这里的MaxLen(n)表示以数组下标n为终点的最长上升子序列的长度
②MaxLen (k) = Max { MaxLen (i):1< i< k 且 ai < ak且 k≠1 } + 1
当然,②也有另一种表述MaxLen (k) = Max { MaxLen (i)+1:1< i < k 且 ai < ak且 k≠1 },本质上是一样的。使用转移方程之前,要初始化 MaxLen(n) = 1
实现代码
//java
class MaxSubLenTool{
public static int getMaxSubLen(int[]nums){
if(nums == null || nums.length <= 0)
return -1;
if(nums.length == 1)
return 1;
int seqlen[] = new int[nums.length];//对应下标所在数字为升序终点的最大长度
for(int i = 0 ;i < nums.length ;i ++)
seqlen[i] = 1;
int maxLen = 1;
for(int i = 1 ; i < nums.length ; i ++){
for(int j = i-1 ; j >= 0; j --){
if(nums[j] < nums[i] && seqlen[j]+1 > seqlen[i]){
System.out.println("nums[j] = "+nums[j]+",nums[i] = "+nums[i]);
seqlen[i] = seqlen[j] + 1;
}
}
if(seqlen[i] > maxLen)
maxLen = seqlen[i];
}
for(int key:seqlen)
System.out.println(key);
System.out.println("res");
return maxLen;
}
}