Leetcode 2407. Longest Increasing Subsequence II

Leetcode 2407. Longest Increasing Subsequence II

You are given an integer array nums and an integer k.

Find the longest subsequence of nums that meets the following requirements:>

复制代码
1. The subsequence is strictly increasing and
2. The difference between adjacent elements in the subsequence is at most k.

Return the length of the longest subsequence that meets the requirements.

A subsequence is an array that can be derived from another array by deleting some or no > > elements without changing the order of the remaining elements.

假设我们用一个数组 dp \text{dp}\[\] dp\[\]来存储以当前元素为结尾的最长递增子数列, 我们可以考虑对数组顺序循环,对每一个值 nums i \text{nums}i numsi,满足constraint: j < i , nums j + k > = nums i j < i, \text{nums}j + k >= \text{nums}i j<i,numsj+k>=numsi的条件所有 j j j,求 max ⁡ dp j \max \text{dp}j maxdpj。

max ⁡ j < i dp j s . t . nums j + k > = nums i \max_{j < i}\text{dp}j \quad s.t. \text{nums}j + k >= \text{nums}i j<imaxdpjs.t.numsj+k>=numsi

为了解这个问题,我们可以构造一个线段树 tree \text{tree} tree,其index可以表示 nums \text{nums}\[\] nums\[\]中的元素值的范围,对应value表示以该元素范围为结尾的最长递增子序列,那么在循环中我们只要查询 tree nums \[ j − k : nums j − 1 ] \text{tree}\\text{nums}\[j-k : \text{nums}j-1] treenums\[j−k:numsj−1] 即可。这样的时间复杂度相当于扫一遍长度为 N N N的数组 nums \texttt{nums} nums,每次对最大数值范围为 M M M的线段树进行查询和更新操作,总复杂度为 O ( N log ⁡ M ) \mathcal{O}(N \log M) O(NlogM). 以下为code:

复制代码
class Solution {
public:

    void update(vector<int>& tree, int v, int tl, int tr, int pos, int new_val) {
        if (tl == tr) {
            tree[v] = max(new_val, tree[v]);
        } else {
            int tm = (tl + tr) / 2;
            if (pos <= tm)
                update(tree, v*2, tl, tm, pos, new_val);
            else
                update(tree, v*2+1, tm+1, tr, pos, new_val);
            tree[v] = max(tree[v*2], tree[v*2+1]);
        }
    }

    int get(vector<int>& tree, int v, int tl, int tr, int l, int r) {
        if (l > r) return 0;
        if (tl == l && tr == r) return tree[v];

        int tm = (tl + tr) / 2;
        return max(
            get(tree, v*2,   tl,   tm, l, min(tm, r)),
            get(tree, v*2+1, tm+1, tr, max(tm+1, l), r)
        );
    }

    int lengthOfLIS(vector<int>& nums, int k) {
        vector<int> tree(400000, 0);
        for (auto it = nums.begin(); it != nums.end(); ++it) {
            int sub = get(tree, 1, 1, 100000, max(1,(*it)-k), (*it)-1);
            update(tree, 1, 1, 100000, *it, sub+1);
        }
        return tree[1];
    }
};
相关推荐
一去不复返的通信er2 小时前
贪心算法-合并区间(LeetCode 56)
算法·leetcode·贪心算法
Shaoshing3 小时前
LeetCode100 49. 字母异位词分组
java·算法
YFJ_mily3 小时前
第二届区块链技术与基础模型国际学术会议(BTFM2027)
算法·区块链·能源·智能系统·rdlink研发家·机器人自动化
汤姆宝库3 小时前
收官深拆:第一性原理、产业电网与未来推演
大数据·人工智能·算法
moshuying5 小时前
块扩散 + GDN 改造:Clover 把「并行生成」塞进了 Agent 的长上下文里
前端·算法
没落之王6 小时前
历史系统建模:宋初太祖太宗「再立天庭」秩序重构推演
人工智能·算法·重构
INGNIGHT6 小时前
91 · 最小调整代价(序列dp)
数据结构·算法·leetcode
moshuying6 小时前
扩散模型开始写代码、开网页了:350 亿参数,速度比 Jev 快一倍
前端·算法
小超人诞生日记6 小时前
C++ 异常机制详解:从抛出捕获到异常安全
c++·算法