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] nums[i],满足constraint: j < i , nums [ j ] + k > = nums [ i ] j < i, \text{nums}[j] + k >= \text{nums}[i] j<i,nums[j]+k>=nums[i]的条件所有 j j j,求 max ⁡ dp [ j ] \max \text{dp}[j] maxdp[j]。

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<imaxdp[j]s.t.nums[j]+k>=nums[i]

为了解这个问题,我们可以构造一个线段树 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] tree[nums[j]−k:nums[j]−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];
    }
};
相关推荐
l1t4 分钟前
利用DuckDB列表一句SQL输出乘法口诀表
数据库·sql·算法·duckdb
一只会写代码的猫15 分钟前
深度解析 Java、C# 和 C++ 的内存管理机制:自动 vs 手动
java·jvm·算法
高山有多高16 分钟前
堆应用一键通关: 堆排序 +TOPk问题的实战解析
c语言·数据结构·c++·算法
我命由我1234518 分钟前
Java 开发 - 简单消息队列实现、主题消息队列实现
java·开发语言·后端·算法·java-ee·消息队列·intellij-idea
2501_9412374518 分钟前
高性能计算通信库
开发语言·c++·算法
1白天的黑夜124 分钟前
递归-二叉树中的剪枝-814.二叉树剪枝-力扣(LeetCode)
c++·leetcode·剪枝·递归
程序猿追26 分钟前
Ascend C编程范式总结:与CUDA的异同对比
c语言·开发语言·算法
前进之路92 小时前
Leetcode每日一练--47
数据结构·算法·leetcode
2501_941236213 小时前
C++与Node.js集成
开发语言·c++·算法
云边有个稻草人6 小时前
部分移动(Partial Move)的使用场景:Rust 所有权拆分的精细化实践
开发语言·算法·rust