zoukankan      html  css  js  c++  java
  • [leetcode] Longest Increasing Subsequence

    Given an unsorted array of integers, find the length of longest increasing subsequence.

    Example:

    Input: [10,9,2,5,3,7,101,18]
    Output: 4 
    Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. 

    Note:

    • 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?


    分析:这个题目翻译一下:求最长递增子序列长度,注意这里递增序列可以不连续。这是一个经典的动态规划问题。
    最经典的一个动态规划做法如下:
    1、维持一个dp数组,dp[i]用来保存以i位置元素结尾的最长递增子序列长度;
    2、对于边界,当i=0时很容易得出:dp[0]=1;
    3、对于状态转移方程,我们假设从0~x-1都已经确定,对于以nums[x]结尾的子串,我们需要遍历0~x-1,比较nums[x]与nums[j](0<=j<=x-1),在nums[j]<nums[x]的前提下,dp[x]=max{1,dp[j]+1}。
    4、注意这里dp保存的一定是以dp[i]结尾的最长递增子序列长度。所以求全部数组最长递增子序列需要将dp数组遍历求最大。
     
    举个例子,对于nums=[1,3,6,7,9,4,10,5,6],我们要找以第6个位置,也就是nums[6]=10结尾的字串中最长的递增字串长度。
    我们假设已经知道dp[0]——dp[5]=[1,2,3,4,5,3],那么对于nums[6],首先找到nums中所有比10小的数字,j从0——5遍历,发现每个数字都比10小,于是就计算dp[6]=max{1,dp[0]+1,dp[1]+1,...,dp[5]+1}=6。
     
    代码如下:
     1 class Solution {
     2     public int lengthOfLIS(int[] nums) {
     3         if ( nums == null || nums.length == 0 ) return 0;
     4         int[] dp = new int[nums.length];
     5         dp[0]=1;
     6         for ( int i = 1 ; i < nums.length ; i ++ ){
     7             int max_t = 1;
     8             for ( int j = 0 ; j < i ; j ++ ){
     9                 if ( nums[j] < nums[i] ){
    10                     max_t = Math.max(max_t,dp[j]+1);
    11                 }
    12             }
    13             dp[i]=max_t;
    14         }
    15         int res = 0;
    16         for ( int i : dp ) {
    17             res = Math.max(i,res);
    18         }
    19         return res;
    20     }
    21 }

          运行时间13ms,击败65.06%。

          注意!!!这是最经典的方法啦,不要想着对这个思路进行改进啦。我已经尝试改变dp的含义等等,发现都不可以。因此遇到最长递增子序列,就用这个方法就行啦!!!一定要注意dp数组的含义。


    思路二:使用dp+二分查找。时间复杂度o(nlogn)。
    1、dp[i]用来存储所有长度为i+1的递增序列中,末尾最小的元素的值;(所以dp数组一定是递增的!)
    2、边界情况dp[0]=min{nums},因此不需用单独拿出来讨论;
    3、状态转移方程,对于x位置,假设dp[0]——dp[x-1]都已知。有两种情况:第一种,nums[x]比dp[x-1]大,那么dp[x] = nums[x],并且size++;第二种,dp[k]<nums[x]<=dp[k+1],dp[k]=nums[x]。
    代码如下:
     1 class Solution {
     2     public int lengthOfLIS(int[] nums) {
     3         int[] dp = new int[nums.length];
     4         int len = 0;
     5         for ( int num : nums ){
     6             int i = 0;
     7             int j = len;
     8             while ( i < j ){
     9                 int mid = ( i + j ) / 2;
    10                 if ( dp[mid] < num ){
    11                     i = mid + 1;
    12                 }else {
    13                     j = mid  ;
    14                 }
    15             }
    16             dp[i] = num;
    17             if ( i == len ) len++;
    18         }
    19         return len;
    20     }
    21 }

          运行时间1ms。

     
  • 相关阅读:
    Mysql流程控制语句和存储过程
    第七章 MySQL基础
    第六章 操作数据
    第四章 数据库操作
    第三章 使用MySQL图形化工具
    第二章 初识MySQL
    第一章 数据库基础
    Live555源码学习02 ---- 框架
    Live555源码学习01 ---- 编译
    SRS4.0之RTMP转WebRTC02 ---- RTMP推流到SRS
  • 原文地址:https://www.cnblogs.com/boris1221/p/9325545.html
Copyright © 2011-2022 走看看