最长升序子序列,很经典的问题,发现写博客的真是不负责任啊,瞎写一通根本没有任何逻辑,本文主要参考http://yzmduncan.iteye.com/blog/1546503,加上自己的理解和实现的代码。
最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列。设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为:
dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i].
public static int lengthOfLIS(int[] nums) {
if(nums.length<2){
return nums.length;
}
int[] count=new int[nums.length];
for(int i=0; i<count.length; i++){
count[i]=1;
}
int re=1;
for(int i=1; i<nums.length; i++){
int max=0;
for(int j=0; j<i; j++){
if(nums[j]<nums[i]&&count[j]>max){
max=count[j];
}
}
count[i]=max+1;
}
for(int i=0; i<count.length; i++){
if(count[i]>re){
re=count[i];
}
}
return re;
}
考虑两个数a[x]和a[y],x<y且a[x]<a[y],且dp[x]=dp[y],当a[t]要选择时,到底取哪一个构成最优的呢?显然选取a[x]更有潜力,因为可能存在a[x]<a[z]<a[y],这样a[t]可以获得更优的值。在这里给我们一个启示,当dp[t]一样时,尽量选择更小的a[x].
按dp[t]=k来分类,只需保留dp[t]=k的所有a[t]中的最小值,设d[k]记录这个值,d[k]=min{a[t],dp[t]=k}。
这时注意到d的两个特点(重要):
1. d[k]在计算过程中单调不升;
2. d数组是有序的,d[1]<d[2]<..d[n]。
利用这两个性质,可以很方便的求解:
1. 设当前已求出的最长上升子序列的长度为len(初始时为1),每次读入一个新元素x:
2. 若x>d[len],则直接加入到d的末尾,且len++;(利用性质2)
否则,在d中二分查找,找到第一个比x小的数d[k],并d[k+1]=x,在这里x<=d[k+1]一定成立(性质1,2)。
private static int binarySearch(int[] nums, int i, int j, int target){
while(i<j){
int mid=(i+j)>>>1;
if(target>nums[mid]&&target<=nums[mid+1]){
return mid;
}else if(nums[mid]<target){
i=mid+1;
}else{
j=mid-1;
}
}
return 0;
}
public static int lengthOfLIS2(int[] nums) {
if(nums.length<2){
return nums.length;
}
int len=1;
int[] d=new int[nums.length+1];
d[1]=nums[0];
for(int i=1; i<nums.length; i++){
if(nums[i]>d[len]){
d[++len]=nums[i];
}else{
int j=binarySearch(d, 0, len, nums[i]);
d[++j]=nums[i];
}
<span style="white-space:pre"> </span>//System.out.println(Arrays.toString(d));
}
return len;
}
int nums[]={10, 9, 2, 5, 3, 7, 101, 18}; 在代码中注释部分,每次都打印出d[]的值。
[0, 9, 0, 0, 0, 0, 0, 0, 0][0, 2, 0, 0, 0, 0, 0, 0, 0] //这步体现出了性质2,len的长度没有变,但是同样长度为1,2比9更有潜力,所以把长度为1的字串最大值更新为2.
[0, 2, 5, 0, 0, 0, 0, 0, 0]//这步5比上一步求出的最大字串的最大值2还大,所以len++,d[len]更新为5
[0, 2, 3, 0, 0, 0, 0, 0, 0]
[0, 2, 3, 7, 0, 0, 0, 0, 0]
[0, 2, 3, 7, 101, 0, 0, 0, 0]
[0, 2, 3, 7, 18, 0, 0, 0, 0]