求最长递增子序列

62 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

1、前言

每天一个算法小练习,本篇使用Java实现。

2、题目描述

  给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

  • 1 <= nums.length <= 2500
  • -104 <= nums[i] <= 104

2.1、示例1

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 

2.2、示例2

输入:nums = [0,1,0,3,2,3]
输出:4

2.3、示例3

输入:nums = [7,7,7,7,7,7,7]
输出:1

3、解题思路

新建一个list,用来保存当前访问位置及之前位置对所有长度为i的子序列的最后一个元素值进行比较后的最小值。总之就是让list存储比较小的元素,最后list的长度就是最长子序列的长度。

3.1、贪心+二分查找

class Solution {
    public int lengthOfLIS(int[] nums) {
        List<Integer> resList = new ArrayList<>();
        for(int i = 0; i < nums.length; i++){
            if(resList.isEmpty() || nums[i] > resList.get(resList.size() - 1)){
                //判断是否是较小的值,是则加入进来
                resList.add(nums[i]);
            }else{
                //begin是在resList中第一个大于该数的下标
                int begin = 0, end = resList.size() - 1, mid = 0;
                //二分查找,遍历当前元素的前元素
                while(begin <= end){
                    mid = (begin + end) >> 1;
                    if (resList.get(mid) < nums[i]){
                        begin = mid+1;
                    }else if(mid == 0|| resList.get(mid-1) < nums[i]){
                        break;
                    }else{
                        end = mid - 1;
                    }
                }
                //如果当前点的值大于前面的点,则更新
                resList.set(mid, nums[i]);
            }
        }
        return resList.size();
    }
}

执行结果:

image.png

  • 时间复杂度:O(nlogn)O(n log n),n为nums数组的长度,因为要遍历数组然后进行二分查找。

  • 空间复杂度:O(n)O(n)

好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊