给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],
它的长度是 4。
说明:
- 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
- 你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
思路:在java代码里面
代码:
// class Solution {
// //套路(自顶向下)
// //去用于
// //改非递归(自底向上)
// public static int[] f = new int[10000];
// public static int[] p = new int[10000];
// public static int n;
// public static int robot(int idx,int[] nums){
// if (idx < 0){
// return 0;
// }
// if(f[idx] > 0){
// return f[idx];
// }
// int ans = 0;
// for (int i = 0; i < idx ;i++){
// if(nums[idx] > nums[i]){
// ans = Math.max(ans,robot(i,nums));
// }
// }
// f[idx] = ans + 1;
// return ans +1;
// }
// public int lengthOfLIS(int[] nums) {
// for(int i = 0;i<10000;i++){
// f[i] =0;
// }
// n = nums.length;
// for(int i = 0;i< n;i++){
// p[i] = nums[i];
// }
// p[n] = 1000000000;
// n++;
// for(int idx = 0;idx < n;idx++){
// int ans = 0;
// for (int i = 0; i < idx ;i++){
// if(p[idx] > p[i]){
// ans = Math.max(ans,f[i]);
// }
// }
// f[idx] = ans + 1;
// }
// return f[n-1] -1;
// }
// }
// class Solution {
// public int lengthOfLIS(int[] nums) {
// if(nums.length<1) return 0;
// //存储,以 i 元素结尾的最长公共子序列长度
// int[] deep = new int[nums.length];
// deep[0] = 1;
// int res = 1;
// //遍历元素,向后迭代,动态规划
// for(int i=1;i<nums.length;i++){
// deep[i] = 1;
// //遍历 nums[j] 0 ---> i-1
// for(int j=0;j<i;j++){
// //如果nums[j] < nums[i]
// //则deep[i] 有扩张可能性 deep[j]+1,
// //deep[i] 只记录最大值
// if(nums[j] < nums[i]){
// deep[i] = Math.max(deep[j]+1,deep[i]);
// }
// }
// //res只记录整个过程中出现的最大值,
// if(res<deep[i]) res=deep[i];
// }
// return res;
// }
// }
class Solution {
public int lengthOfLIS(int[] nums) {
// write your code here
if(nums.length == 0){
return 0;
}
// len表示当前最长的升序序列长度(为了方便操作tails我们减1)
int len = 0;
// tails[i]表示长度为i+1的升序序列其末尾的数字,tail表示长度为i+1的尾数最小的那个数字[2,3][2,5]长度为2的最小的尾数为3 tail[1] = 3
int[] tails = new int[nums.length];
tails[0] = nums[0];
// 根据三种情况更新不同升序序列的集合
for(int i = 1; i < nums.length; i++){
if(nums[i] < tails[0]){
tails[0] = nums[i];
} else if (nums[i] > tails[len]){
tails[++len] = nums[i];
} else {
// 如果在中间,则二分搜索
tails[binarySearch(tails, 0, len, nums[i])] = nums[i];
}
}
return len + 1;
}
private int binarySearch(int[] tails, int min, int max, int target){
while(min <= max){
int mid = min + (max - min) / 2;
if(tails[mid] == target){
return mid;
}
if(tails[mid] < target){
min = mid + 1;
}
if(tails[mid] > target){
max = mid - 1;
}
}
return min;
}
}
python版:
class Solution:
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
#可用使用动态规划,用数组res[i]表示到i 时的最长上升序列数,取在i前面比num[i]小的数的最长在上升序列来更新res[i],所以时间复杂度为 O(n2)。
if nums == []:
return 0
tail = []
tail.append(nums[0]) #tail表示最长升序列的长度为i的最后一个数字
maxlen = 0 #定义tail的下标也就是最长升序列的长度-1
for i in range(len(nums)):#遍历nums数组
if nums[i] > tail[maxlen]: #如果nums数组比当前的最长升序列的最后一位数字大,那么就添加进去
tail.append(nums[i])
maxlen += 1
else:
#就进行二分查找,找到tail数组中
left,right = 0,maxlen
while left <= right:
mid = (left + right) // 2
if tail[mid] < nums[i]:
left = mid + 1
else:
right = mid - 1
tail[left] = nums[i]
return maxlen+ 1