class Solution { public int lengthOfLIS(int[] nums) { int []tails=new int[nums.length]; int size=0; for(int x:nums) { int i=0,j=size; while(i!=j) { int m=i+(j-i)/2; if(tails[m]<x) i=m+1; else j=m; } tails[i]=x; if(i==size)++size; } return size; } }
这题是典型的考察dp并且是非常直白的..不像有些题目很绕,想半天才知道是dp
dp的做法就是分配一个数组, dp[i] 代表 第i 个位置的最长递增数组长度
递推公式 if (num[i]>num[k]) dp[i]=max(dp[k]+1,dp[i]) 0<=k<i 时间复杂度 O(n2) n是数组长度; 其实精确计算复杂度应该是O(1+2+3+...+n) = O(n*(n-1)/2) = O( (n2-n)/2)
好了, 上面给出的更加高效的办法, 用二分查找做到了 O(nlogn);
原理如下
1 数组长度为n, 所以我们可以找出 长度 为 1,2,3,4, .... k 的递增数组
2 设定 数组= 1,2,3,0
长度=1 递增数组 [1], [2] , [3] , [0]
长度=2 递增数组 [1,2] [2,3] [1,3]
长度=3 [1,2,3]
取每个数组的末尾值, 并且值最小 分别是 0 , 2, 3 ; 这几个数的长度是3, 所以答案就是3
3 实现过程
分配一个数组来存放不同长度的递增数组的末尾值的最小取值.. 非常绕
int tail = new int[]
遍历数组;如果 num[i] 比 tail 末尾值还大, 插入末尾
如果nums[i] 值在tail 的之内; 找到一个位置替换, 具体是 tail[i] < num[j] <= tail[i+1]
因为用到了二分查找, 所以复杂度变成了logn