【题目】:
给定数组arr,返回arr的最长递增子序列。
【例子】:
arr=[10,22,9,33,21,50,41,60,80],返回的最长递增子序列为[10,22,33,41,60,80]长度为6。
解法 1
思路:
1.定义长度为n的dp数组,dp[i]表示为arr[i]结尾的最长递增子序列的长度。
2.对于第一个数arr[0]来说dp[0]=1,依次求出以i结尾的最长递增子序列
3.对于dp[i],求arr[i]结尾的最长递增子序列,在arr[0..i-1]中选出比arr[i]小且长度最长的
dp[j] , dp[i] = Math.max( dp[0…i-1] , dp[i] );如果所有的 dp[0…i-1] 都比 dp[i] 大,则 dp[i]=1;
代码:
//最优解:
public static int LongestSubString(int arr[])
{
int len=0;
if(arr==null||arr.length==0)
return 0;
int dp[]=new int[arr.length];
dp[0]=1;
//dp[i] 表示到i为止是最长递增子序列的长度
for(int i=1;i<arr.length;i++)
{
dp[i]=1;
for(int j=0;j<i;j++)
{
if(arr[i]>arr[j])
{
//求dp[i]时遍历,dp[0...i-1],找出arr[j]<arr[i]小且dp[j]是最大的
//dp[i]=dp[j]+1;
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
}
for(int i=0;i<arr.length;i++)
{
len=Math.max(dp[i],len);
}
return len;
//最优值,求出dp[i]之后要求出递增子序列[10,22,33,41,60,80]
//先找到最大dp[i],从后往前,如果dp[i]==dp[j]+1,且arr[i]>arr[j],则可知arr[j]是子序列中
//arr[i]前面的数.
public generateLIS(int arr[],int dp[])
{
int k=0;
int index=0;
int len=0;
for(int i=0;i<arr.length;i++)
{
if(dp[i]>len)
{
len=dp[i];
index=i;
//找到递增子序列中的最后一个元素[10,22,33,41,60,80]中的80,
}
}
int subArr[]=new int[len];
subArr[k++]=arr[index];
for(int j=index-1;j>=0;j--)
{
if((dp[index]==dp[j]+1)&&(arr[index]>arr[j]))
{
//从后向前,将属于递增子序列的元素加入到subArr中。
subArr[k++]=arr[j];
index=j;
}
}
for(int j=subArr.length-1;j>=0;j--)
{
System.out.print(subArr[j]+" ");
}
}
解法2
思路
生成 dp 数组时使用二分查找算法来进行。
用ends数组来保存单调序列,这个序列并不是 最优值的单调序列,对于arr[i],如果比 ends 中的每个
数都大时放到 ends 后面,否则用arr[i]代替ends数组中第一个比arr[i]大的数,保持 ends 递增。这样
每一个arr[i]在ends的位置就是 dp[i] 的值。
public static int LongestSubString1(int arr[])
{
if(arr==null||arr.length==0)
return 0;
int l=0,r=0,right=0;
int len=0;
int ends[]=new int[arr.length];
int dp[]=new int[arr.length];
dp[0]=1;
ends[0]=arr[0];
//ends[0]开始时存放arr[0],
for(int i=1;i<arr.length;i++)
{
l=0;
r=right;
//如果arr[i]比 ends 数组中的所有元素都大则放到 ends 后面,
//否则用arr[i]代替ends数组中第一个比arr[i]大的数,保持 ends 递增。
while(l<=r)
{
int mid=(l+r)/2;
if(arr[i]>ends[mid])
{
l=mid+1;
}
else {
r=mid-1;
}
}
right=Math.max(l,right);
ends[l]=arr[i];
dp[i]=l+1;
//arr[i]在数组 ends 中的位置,就是以arr[i]结尾的最长单调子序列的长度。
}
len=right+1;
generateLIS(arr,dp);
return len;
}