300. Longest Increasing Subsequence

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 但是递推表达式不好想
可以想一下 dp存什么 后面的能继续使用
比如输入如下
10 9 2 5 3 4 7

怎样让最大递增子序列是2,3,4 而不是2,5 也就是跳过5 并且让3能接在2的后面
答案是 遍历3之前所有3可以接上的子序列 选择最长的
public int lengthOfLIS(int[] nums) {
    if (nums.length == 0) {
        return 0;
    }
    int[] dp = new int[nums.length];
    dp[0] = 1;
    int maxans = 1;
    for (int i = 1; i < dp.length; i++) {
        int maxval = 0;
        for (int j = 0; j < i; j++) {                         
            if (nums[i] > nums[j]) {//找出所有将nums[i]加入仍然是递增序列的序列
                maxval = Math.max(maxval, dp[j]);//选择长度最大的那个 拼接上nums[i] 这样 就还是最长的子序列
            }
        }
        dp[i] = maxval + 1;
        maxans = Math.max(maxans, dp[i]);
    }
    return maxans;
}
也就是说 从dp[i]是指可以将nums[i]加入之后仍然是递增子序列中 长度最大的那个 
dp[0]到dp[n]分别代表把dp[i]包含进来 最长的递增子序列 然后再取max的就可以了
optimal substructure:
dp[i]=max(dp[j])+1,0j<i
LISlength=max(dp[i]),0i<n
时间复杂度O(n^2)

接下来是follow up 如何把时间复杂度提高到O(nlogn) 看一下solution
public int lengthOfLIS(int[] nums) {
    int[] dp = new int[nums.length];
    int len = 0;
    for (int num : nums) {
        int i = Arrays.binarySearch(dp, 0, len, num);//1.
        if (i < 0) {//2.
            i = -(i + 1);
        }
        dp[i] = num;
        if (i == len) {
            len++;
        }
    }
    return len;
}
1.看一下数组二分查找方法的注释
* @param a the array to be searched
* @param fromIndex the index of the first element (inclusive) to be
*          searched
* @param toIndex the index of the last element (exclusive) to be searched
* @param key the value to be searched for
* @return index of the search key, if it is contained in the array
*         within the specified range;
*         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
*         <i>insertion point</i> is defined as the point at which the
*         key would be inserted into the array: the index of the first
*         element in the range greater than the key,
*         or <tt>toIndex</tt> if all
*         elements in the range are less than the specified key.  Note
*         that this guarantees that the return value will be &gt;= 0 if
*         and only if the key is found.
也就是说 在数组a的fromIndex和endIndex之间找到key所在的位置
比如 a={1,3,5,7,8} fromIndex=0 endIndex=4 key=5
也就是在a的0-4之间找到5的索引 返回值为2
2.
if (i < 0) {
    i = -(i + 1);
}
这段代表什么含义呢 首先看一下i<0的情况
可以从代码注释中看到
if it is contained in the array
*         within the specified range;
*         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  
如果找不到key 那么就返回-(insertion point - 1)
insertion point是指这个key可以插入的位置
比如 a={1,3,5,7,8} fromIndex=0 endIndex=4 key=6
那么insertion point就是4 因为2插入到索引位置为4后 数组变为 {1,2,3,5,6,7,8} 还是有序数组
所以这段代码表示 如果i<0 也就是没找到该值 i也就是-(insertion point - 1)
那么i = -(i + 1) 获取到插入位置

dp存储把当前元素包含之后的最大递增子序列 初始化都为0
之后会在dp中找当前元素的插入位置 并插入 所以dp最开始是有序的 插入元素之后也保持有序 所以可以一直直接使用二分查找

比如输入是:

[0, 8, 4, 12, 2]

那么dp的变化过程如下

dp: [0]

dp: [0, 8]

dp: [0, 4]

dp: [0, 4, 12]

dp: [0 , 2, 12] 

当i == len 表示新的元素的插入位置是在原有递增子序列的最后 也就是可以拼接在原有递增子序列的后面 所以len++

最后 len也就是dp的有效长度 就是最大递增子序列的长度




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值