动态规划:最长递增子序列

84 阅读1分钟

leetcode:300. 最长递增子序列

题目描述

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例

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

求解思路

  • 状态定义

    创建新数组tailstails[i]表示长度为i+1的子数组的最小尾元素。

  • 状态转移

    tails中已经装配的尾元素中进行二分查找,找到第一个大于等于target的尾元素 下标为i

    那么,tails[i] = target,更新最小尾元素。

  • 二分查找的边界处理🌟🌟🌟

    res定义为当前已经装配了尾元素的最大下标。

    定义l = 0, r = res - 1,左闭右闭区间,[l, r]都是target可能存在的位置。

    while循环条件为l <= rl返回需要更新的位置。

    • tails[mid] < target时,l = mid + 1mid以及左侧都小于target。直接更新。
    • tails[mid] >= target时,r = mid - 1mid大于等于target,需要向左找到更小的满足大于等于target的元素。

完整实现

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] tails = new int[nums.length];
        int res = 0;
        for (int num : nums) {
            int l = 0, r = res - 1;
            while (l <= r) {
                int mid = (l + r) / 2;
                if (tails[mid] < num) {
                    l = mid + 1;
                }
                else {
                    r = mid - 1;
                }
            }
            tails[l] = num;
            if (l == res) res++;
        }
        return res;
    }
}