Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18]
,
The longest increasing subsequence is [2, 3, 7, 101]
, therefore the length is 4
. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
思路:分解成子问题,然后由子问题来推倒出最后的大问题。递推公式就是假设dp[i] 表示的物理意义是,以i为最后一个char,到此为止所能够表示的最长的递增子序列,那么递推公式就是 dp[i] = Math.max(dp[j] + 1) if a[j] < a[i]; j is [0,i ) 注意intial是所有元素为1.
class Solution {
// dp[i] = Math.max(dp[j] + 1), j < i && nums[j] < nums[i];
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int[] dp = new int[n];
int globalmax = 1;
Arrays.fill(dp, 1);
for(int i = 1; i < n; i++) {
for(int j = 0; j < i; j++) {
if(nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
globalmax = Math.max(globalmax, dp[i]);
}
return globalmax;
}
}
思路2: NlogN的解法:这个完全是数学的方法,归纳发现出来的。
存长度为i的,最小升序的下标;这个数组是绝对递增的;
详细解释如下:
在1,3,5,2,8,4,6
这个例子中,当到6时,我们一共可以有四种
(1)不同长度
(2)且保证该升序序列在同长度升序序列中末尾最小的升序序列
1
1,2
1,3,4
1,3,5,6
这些序列都是未来有可能成为最长序列的候选人。这样,每来一个新的数,我们便按照以下规则更新这些序列
- 如果
nums[i]
比所有序列的末尾都大,或等于最大末尾,说明有一个新的不同长度序列产生,我们把最长的序列复制一个,并加上这个nums[i]
。 - 如果
nums[i]
比所有序列的末尾都小,说明长度为1的序列可以更新了,更新为这个更小的末尾。 - 如果在中间,则更新那个末尾数字刚刚大于等于自己的那个序列,说明那个长度的序列可以更新了。
比如这时,如果再来一个9,那就是第一种情况,更新序列为
1
1,2
1,3,4
1,3,5,6
1,3,5,6,9
如果再来一个0,那就是第二种情况,更新序列为
0
1,2
1,3,4
1,3,5,6
如果再来一个3,那就是第三种情况,更新序列为
1
1,2
1,3,3
1,3,5,6
前两种都很好处理,O(1)就能解决,主要是第三种情况,实际上我们观察直到6之前这四个不同长度的升序序列,他们末尾是递增的,所以可以用二分搜索来找到适合的更新位置。
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int[] tails = new int[n];
int index = 0;
for(int i = 0; i < nums.length; i++) {
if(nums[i] < nums[0]) {
nums[0] = nums[i];
} else if(nums[i] > nums[index]) {
nums[++index] = nums[i];
} else {
// nums[0] <= nums[i] <= nums[index];
nums[binarySearch(nums, 0, index, nums[i])] = nums[i];
}
}
return index + 1;
}
// find first element index which is greater than target in sorted array;
private int binarySearch(int[] A, int start, int end, int target) {
while(start + 1 < end) {
int mid = start + (end - start) / 2;
if(A[mid] >= target) {
end = mid;
} else {
start = mid;
}
}
if(A[start] >= target) {
return start;
}
return end;
}
}