对于一个数字序列,请设计一个复杂度为O(nlogn)的算法,返回该序列的最长上升子序列的长度,这里的子序列定义为这样一个序列U1,U2...,其中Ui < Ui+1,且A[Ui] < A[Ui+1]。
给定一个数字序列A及序列的长度n,请返回最长上升子序列的长度。
[2,1,4,3,1,5,6],7
返回:4
public class AscentSequence {
    public int findLongest(int[] A, int n) {
        int length = A.length;
        int[] B = new int[length];
        B[0] = A[0];
        int end = 0;
        for (int i = 1; i < length; ++i) {
            // 如果当前数比B中最后一个数还大,直接添加
            if (A[i] >= B[end]) { B[++end] = A[i]; continue;
            } 
            // 否则,需要先找到替换位置
            int pos = findInsertPos(B, A[i], 0, end); B[pos] = A[i];
        }
        for (int i = 0; i < B.length; ++i) {
            System.out.println(B[i]);
        }
        return end+ 1; }
    /**
     * 二分查找第一个大于等于n的位置
     */
    private int findInsertPos(int[] B, int n, int start, int end) {
        while (start < end) {
            int mid = start + (end - start) / 2;// 直接使用(high + low) / 2 可能导致溢出
            if (B[mid] < n) {
                start = mid + 1;
            } else if (B[mid] > n) {
                end = mid ;
            } else {
                return mid;
            }
        }
        return start;
    }
}
 
  class AscentSequence {
public:
    int findLongest(vector<int> A, int n) {
        int dp[1000];
        for(int i=0;i<n;i++){
            dp[i]=1;
        }
        for(int i=1;i<n;i++){
            int tmax=1;
           for(int j=0;j<i;j++){
               if(A[j]<A[i]){
                   tmax=max(tmax,dp[j]+1);
               }
           }
            dp[i]=tmax;
        }
        int ans=1;
        for(int i=0;i<n;i++){
            ans=max(ans,dp[i]);
        }
        return ans;
    }
};
 import java.util.*;
public class AscentSequence {
    public int findLongest(int[] A, int n) {
        int[] dp=new int[n];
        int max=0;
        for(int i=0;i<n;i++){
            dp[i]=1;
            for(int j=0;j<i;j++){
                if(A[i]>A[j]){
                    dp[i]=Math.max(dp[i],dp[j]+1);
                    if(dp[i]>max)
                        max=dp[i];
                }
            }
        }
       return max;
    }
} public int findLongest(int[] A, int n) {
        int[] f = new int[n];//用于存放f(i)值;
        f[0]=1;//以第a1为末元素的最长递增子序列长度为1;
        for(int i = 1;i<n;i++)//循环n-1次
        {
               f[i]=1;//f[i]的最小值为1;
               for(int j=0;j<i;j++)//循环i 次
               {
                      if(A[j]<A[i]&&f[j]>f[i]-1)
                             f[i]=f[j]+1;//更新f[i]的值。
               }
        }
        Arrays.sort(f);
        return f[n-1];
    }
import java.util.*;
public class AscentSequence {
    public int findLongest(int[] A, int n) {
        int[] B = new int[n+1]; B[1] = A[0];
        int len=1,start=0,end=len,mid;
        for(int i = 1;i<n;i++){
        	if(A[i]>B[len]) {len++;B[len] = A[i];}
        	else{
        		start=1;end=len;
        		while(start<=end){
            	  mid=(start+end)/2;
            	  if(B[mid]<A[i]) start=mid+1;
            	  else end=mid-1;
              } B[start] = A[i]; 
        	}
        }
        return len;
    }
}
  原文地址:https://blog.csdn.net/cooper20/article/details/80765897
 共有四种思路 
### 方法 1 暴力搜索(超出时间限制)
  算法
 最简单的方法是尝试寻找所有递增子序列,然后返回递增子序列的最大长度。为此,我们使用递归函数lengthofLIS,该函数返回从当前元素(curpos)向前(包括当前元素)的LIS长度。每次函数调用时,考虑两种情况: 
public class Solution {
    public int lengthOfLIS(int[] nums) {
        return lengthofLIS(nums, Integer.MIN_VALUE, 0);
    }
    public int lengthofLIS(int[] nums, int prev, int curpos) {
        if (curpos == nums.length) {
            return 0;
        }
        int taken = 0;
        if (nums[curpos] > prev) {
            taken = 1 + lengthofLIS(nums, nums[curpos], curpos + 1);
        }
        int nottaken = lengthofLIS(nums, prev, curpos + 1);
        return Math.max(taken, nottaken);
    }
} 复杂度分析
  算法
 在上一个方法中,许多参数相同的递归过程被多次调用。通过将递归调用结果保存在一个二维记忆数组memo中,可以消除冗余的调用。memo[i][j]表示num[i]作为前一个元素放入/不放入LIS,并且num[j]作为当前元素放入/不放入LIS时的最长LIS。(memo[i][j] represents the length of the LIS possible using nums[i]nums[i] as the previous element considered to be included/not included in the LIS, with nums[j]nums[j] as the current element considered to be included/not included in the LIS.)。num表示所给定的数组。 
ps:由暴力递归改写。递归函数可变参数 preIndex、curpos,无后效性,故memo[i][j]中缓存由特定递归过程(preIndex, curpos)计算出的值。考虑到元素的取值范围***,在上一个方法中使用的pre参数(表示LIS中的上一个元素的值)需要替换,这里使用preIndex表示该元素在nums数组中的位置。
public class Solution {
    public int lengthOfLIS(int[] nums) {
        // preIndex的取值范围[-1, nums.length - 1],-1表示无前缀。故长度为nums.length + 1,为了将下标为-1的值放入数组,元素整体向后移一位。
        int memo[][] = new int[nums.length + 1][nums.length];
        for (int[] l : memo) {
            Arrays.fill(l, -1);
        }
        return lengthofLIS(nums, -1, 0, memo);
    }
    public int lengthofLIS(int[] nums, int previndex, int curpos, int[][] memo) {
        // base case
        if (curpos == nums.length) {
            return 0;
        }
        // serach first
        if (memo[previndex + 1][curpos] >= 0) {
            return memo[previndex + 1][curpos];
        }
        // compute and ***
        int taken = 0;
        if (previndex  nums[previndex]) {
            taken = 1 + lengthofLIS(nums, curpos, curpos + 1, memo);
        }
        int nottaken = lengthofLIS(nums, previndex, curpos + 1, memo);
        memo[previndex + 1][curpos] = Math.max(taken, nottaken);
        return memo[previndex + 1][curpos];
    }
} 复杂度分析
  算法
 动态规划方法依赖于这样一个事实——以i元素结尾的最长子序列不依赖于其后续元素。因此,如果已知以i元素结尾的LIS长度,可以求出以i+1元素结尾的LIS长度(通过向前搜索,尝试将i+1元素追加至其后)。
 创建数组dp来存储相关数据。dp[i]表示以索引i元素作为结尾的子序列的最大长度。为了求解dp[i],尝试将当前元素(nums[i])追加到每一个既有的递增子序列中,使得添加完当前元素后的新序列仍然是递增序列,若无法添加至仍以既有子序列,则以i元素结尾的LIS长度为1。dp[i]的表达式为: 
dp[i] = max(dp[j]) + 1, 0 nums[j]
即,对于dp[i],求nums[i]结尾的最长递增子序列,在nums[0..i-1]中选出比nums[i]小且长度最长(dp[j] max)的。
最后,dp[i]的最大值即为所求答案,
LIS = max(dp[i]), 0 <= i < n
ps:原著英文较差,此处意译。
public class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[] dp = new int[nums.length];
        dp[0] = 1;
        int maxans = 1;
        for (int i = 1; i < dp.length; i++) {
            int maxval = 0;
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    maxval = Math.max(maxval, dp[j]);
                }
            }
            dp[i] = maxval + 1;
            maxans = Math.max(maxans, dp[i]);
        }
        return maxans;
    }
} 复杂度分析
  算法
 方法3花费了大量时间寻找最大dp[j]上(第二个for循环),如果dp[]是一个递增数列,那么我们可以使用二分查找进行优化,使得整个算法的复杂度下降到O(nlogn)。方法3中dp[i]保存了以nums[i]元素结尾的LIS长度,这里我们使用dp[i]保存所有长度为i+1的递增子序列中末尾元素的最小值。根据这个最小值,可以判断num数组中的后续元素是否可以追加到既有IS中以形成更长的IS。由于dp数组是递增的,所以可以使用二分查找。
 举例: 
nums: 2 1 5 3 6 4 8 9 7
dp[]: 2.........// 遍历至nums[0],当前长度为1的子序列末尾的最小值为2.
dp[]: 1.........// 遍历至nums[1],nums[1]
dp[]: 1 5.......// nums[2],nums[2]
dp[]: 1 3.......// dp[0]
dp[]: 1 3 6.....// num[4] > dp[2],可形成长度为3的子序列。
dp[]: 1 3 4.....// dp[1]
dp[]: 1 3 4 8...// num[6] > dp[2],形成更长的子序列。
dp[]: 1 3 4 8 9.// 形成更长的子序列
dp[]: 1 3 4 7 9.// dp[2]
最终,dp.size = 5,表示LIS=5,且所有该长度序列中最小以9结尾。
public class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        int len = 0;
        for (int num : nums) {
            int i = Arrays.binarySearch(dp, 0, len, num);
            if (i < 0) {
                i = -(i + 1);
            }
            dp[i] = num;
            if (i == len) {
                len++;
            }
        }
        return len;
    }
} 复杂度分析
  参考:
 https://leetcode.com/problems/longest-increasing-subsequence/solution/ 
classAscentSequence {public:intfindLongest(vector<int> A, intn) {if(n==0) return0;vector<int> hash(n);intans=0;for(inti=0;i<n;i++){hash[i]=1;for(intj=i-1;j>=0;j--){if(A[i]>A[j]){if(hash[j]+1>hash[i]){hash[i]=hash[j]+1;if(hash[i]>ans)ans=hash[i];}}}}returnans;}};
public class AscentSequence {
    public int findLongest(int[] arr, int n) {
        // 时间复杂度 O(n*lgn)
        List<Integer> list = new ArrayList<>(n);
        for(int i:arr){
            if(list.isEmpty()||i>list.get(list.size()-1))
                list.add(i);
            else
                list.set(getIndex(list,i,0,list.size()-1),i);
        }
        return list.size();
    }
    public int getIndex(List<Integer> list,int target,int L,int R){
        while(L<R){
            int mid = L+((R-L)>>1);
            if(list.get(mid)<target)
                L = mid+1;
            else
                R = mid;
        }
        return L;
    }
}
                                                                                    bisect模块 import bisect class AscentSequence: def findLongest(self, A, n): res=[] for val in A: index=bisect.bisect_left(res,val) if index==len(res): res.append(val) else: res[index]=val return len(res) class AscentSequence: def findLongest(self, A, n): temp=[10**10]*n temp[0]=A[0] res=[1] for i in range(1,n): pos=self.get_index(temp,A[i]) res+=[pos+1] temp[pos]=A[i] return max(res) def get_index(self,nums,target): low,high=0,len(nums)-1 pos=0 while low<high: mid=(low+high)//2 if nums[mid]<target: low=mid+1 else: high=mid pos=high return pos
class AscentSequence {
public:
    int findLongest(vector<int> A, int n) {
        int B[n+1];
        B[1] = A[0];
        int l=1,s=0,e=l,m;
        for(int i=1;i<n;i++)
        {
            if(A[i]>B[l])
            {
                l++;
                B[l] = A[i];             }else{                 s = 1;                 e = l;                 while(s<=e)                 {                     m = (s+e)/2;                     if(B[m]<A[i])                         s = m+1;                     else                         e = m-1;                 }                 B[s] = A[i];             }         }         return l;
    }
};
 class AscentSequence {
public:
    int findLongest(vector<int> A, int n) {
        // write code here
        vector<int> dp(n,0);
        int res=0;
        dp[0]=1;
        for(int i=0;i!=n;i++){
            int max=0,j=0;
            while(j<i){
                if(A[j]<A[i]&&dp[j]>max)
                    max=dp[j];
                j++;
            }
            dp[i]=max+1;
        }
        for(int i=0;i!=n;i++)
            if(res<dp[i])
                res=dp[i];
        return res;
    }
};
 class AscentSequence {
public:
    int findLongest(vector<int> A, int n) {
        if(n==1)
            return 1;
        vector<int> maxLen(n,1);
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(A[i]>A[j])
                    maxLen[i]=max(maxLen[i],maxLen[j]+1);
            }
        }
        int val=maxLen[0];
        for(int i=0;i<n;i++)
        {
            if(maxLen[i]>val)
                val=maxLen[i];
        }
        return val;
    }
};
package alex.suda.dp;
import java.util.Scanner;
public class test1 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scanner = new Scanner(System.in);
		while (scanner.hasNext()) {
			int n = scanner.nextInt();
			int[] A = new int[n];
			for (int i = 0; i < n; i++) {
				A[i] = scanner.nextInt();
			}
			System.out.print(findLongest(A, n));
		}
	}
	public static int findLongest(int[] A, int n) {
		// 以[2,1,4,3,1,5,6]为例。使用i来表示当前遍历的位置:
		// i = 1 时,最长递增序列为{1} ,序列长度为1
		// i = 2时,1 < 2 所以得丢弃2 重新建立最长递增序列{1},序列长度为1
		// i = 3时,4>2,4>1 最长递增序列为{2,4} {1,4},长度为2
		// 以此类推,可得:d[i+1] = max{1,d[k]+1},其中对于所有的k<= i ,A[i+1] > A[k] 
		// d[i] 表示A数组的前i个元素当中,最长递增序列的长度
		int[] d = new int[n];
		for (int i = 0; i < n; i++) {
			d[i] = 1; // 初始化默认长度
			for (int j = 0; j < i; j++) { // 前面最长的序列
				if (A[i] > A[j] && d[j] + 1 > d[i]) { // 增加了当前的数之后,大于原来的长度,就更新
					d[i] = d[j] + 1;
				}
			}
		}
		int maxDis = Integer.MIN_VALUE;
		for(int i=0;i<n;i++){
			if(d[i] > maxDis){
				maxDis = d[i];
			}
		}
		return maxDis;
	}
}
import java.util.*;
public class AscentSequence {
    public int findLongest(int[] A, int n) {
        // write code here
        int[] dp = new int[n];
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < n; ++i) {
            if (i == 0) {
                dp[i] = 1;
            } else {
                dp[i] = 1;
                for (int j = i - 1; j >= 0; --j) {
                    if (A[j] < A[i]) {
                        dp[i] = Math.max(dp[i], dp[j] + 1);
                    }
                }
            }
            max = Math.max(dp[i], max);
        }
        return max;
    }
}
//C++           O(n^2)解
//时间复杂度为0(n^2)
class AscentSequence {
public:
    int findLongest(vector<int> A, int n) {
        // write code here
		vector<int>vi(n);
		for(int i = 0; i < n; i++)
            vi[i] = 1;
        for(int i = 1;i < n; i++)
            for(int j = 0;j < i;j++){
                if(A[i] > A[j]){
                    vi[i] =vi[i]>(vi[j]+1)?vi[i]:vi[j]+1;
                }
            }
        sort(vi.begin(),vi.end());
        return vi[n-1];
    }
};