LeetCode 300. 最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [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
                
        

猜你喜欢

转载自blog.csdn.net/u014626513/article/details/81094503