最长子序列

本文介绍了如何解决最长递增子序列(LIS)问题,提供了两种解法,包括一个时间复杂度为O(n^2)的直接遍历方法和一个优化后的O(nlog(n))解决方案。优化的解法利用二分查找在已有的子序列中快速找到合适的插入位置,从而减少查询时间。代码实现中展示了如何应用二分查找来构建辅助数组,以便于找到每个阶段的最长子序列。
摘要由CSDN通过智能技术生成
  • 题目:最长子序列
    • 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
    • 子序列可以不连续,但是得按原数组中的相对位置关系
    • 示例 1:
      	  输入:nums = [10,9,2,5,3,7,101,18]
      	  输出:4
      	  解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
      	  示例 2:
      	  - 输入:nums = [0,1,0,3,2,3]
      	  输出:4
      	  示例 3:
      	  - 输入:nums = [7,7,7,7,7,7,7]
      	  输出:1
      
    • 提示:
    • 1 <= nums.length <= 2500
      -104 <= nums[i] <= 104
    • 进阶:
    • 你可以设计时间复杂度为 O(n2) 的解决方案吗?
      你能将算法的时间复杂度降低到 O(n log(n)) 吗?
  • 思路:
    • 先得把[[数组]]规定以哪个位置结尾划分子阶段。以0~i位置划分
    • 得到子数组(子阶段)后再进行判断每个阶段内最长子序列
  • 解法一:O(n^2)
    • 遍历左边比arr(i)小的值,dp()+1就是i的子序列
  • 解法二:O(N*logN)
    • 思路:遍历的复杂度n省不了,可以省每个位置向前查询时把前面所有遍历一遍的n
    • 要省略向前查询的n需要利用之前的阶段产生结果从而不用遍历
    • 操作:创建一个辅助数组(end),对于i位的数,提供i之前最长子序列长度为0~有效值之间的最小结尾。所以只要i位的数比某个最小结尾大,则i位的最长子序列的长度为那个最小结尾+1 。
    • 如何构建辅助数组:
      • 操作:i位置先在end数组里找到最靠右(即最大)且比i位置小的数。往右一格填上i的值
      • 思想:对于i位置来说,有用的只有每个长度的最长子序列的结尾数。之前数据的排列顺序无用。
      • 因为假设之前已经存在了每个长度的最长子序列的结尾数,所以找到比某个结尾数大,i的长度是其+1。
      • 因为子序列的结尾数一定和最长长度正相关。所以可以用二分法来加快查询每个长度的最长子序列的结尾数的过程
    • 代码:
    • 	    (- // 本题测试链接 : https://leetcode.com/problems/longest-increasing-subsequence
      	    public class Code03_LIS {
      	    public static int lengthOfLIS(int[] arr) {
      	    if (arr == null || arr.length == 0) {
      	    return 0;
      	    }
      	    int[] ends = new int[arr.length];
      	    ends[0] = arr[0];
      	    int right = 0;
      	    int l = 0;
      	    int r = 0;
      	    int m = 0;
      	    int max = 1;
      	    for (int i = 1; i < arr.length; i++) {
      	    l = 0;
      	    r = right;
      	    while (l <= r) {//二分的过程
      	    m = (l + r) / 2;
      	    if (arr[i] > ends[m]) {
      	    l = m + 1;
      	    } else {
      	    r = m - 1;
      	    }
      	    }
      	    right = Math.max(right, l);//最大的有效值
      	    ends[l] = arr[i];
      	    max = Math.max(max, l + 1);
      	    }
      	    return max;
      	    } 
      	    })
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值