最长递增子序列的长度(LIS)使用线段树

最长递增子序列的长度(lis)使用线段树

段树是一种多功能的数据结构,旨在以对数时间复杂度回答范围查询和执行数组更新操作,其中每个节点存储与数组中特定范围的元素相关的信息。

最长递增子序列(LIS)问题的背景下,需要确定给定序列中元素按递增顺序排序的最长子序列的长度,可以利用线段树来高效计算数组中最长递增子序列的长度。

这种方法与传统方法相比显著降低了时间复杂度,并在基因组学、自然语言处理和模式识别等领域有许多应用。本文探讨了段树的基本原理,并展示了它们在解决最长递增子序列问题中的潜力。

语法

Segment Tree build function −

void build(vector &tree, const vector &arr, int start, int end, int index)

Segment Tree query function −

int query(const vector &tree, int start, int end, int l, int r, int index)

段树更新函数 −

void update(vector &tree, const vector &arr, int start, int end, int pos, int value, int index)

算法

使用线段树找到最长递增子序列(LIS)的长度的算法如下 –

初始化表示输入序列的数组。

使用与输入序列相同大小的段树进行初始化使用build函数构建线段树

处理输入序列的每个元素。

For each element, query the Segment Tree to find the maximum length of LIS ending at the current element.

Update the Segment Tree using the update function.

对输入序列中的所有元素重复执行步骤4-6。

The final answer is the maximum value stored in the Segment Tree.

Approach 1: Using simple Segment Tree

In this approach, we implement a simple Segment Tree without any optimization techniques such as lazy propagation.

Example-1

The program below demonstrates how to find the Length of Longest Increasing Subsequences (LIS) using a simple Segment Tree in C++. The build, query, and update functions are used to construct the Segment Tree, retrieve the maximum length of LIS ending at a specific element, and update the Segment Tree with new LIS lengths, respectively. The lengthOfLIS function iterates through each element in the input sequence and computes the LIS length using the Segment Tree.

#include #include #include using namespace std;void build(vector &tree, const vector &arr, int start, int end, int index) {   if (start == end) {      tree[index] = arr[start];   } else {      int mid = start + (end - start) / 2;      build(tree, arr, start, mid, 2 * index + 1);      build(tree, arr, mid + 1, end, 2 * index + 2);      tree[index] = max(tree[2 * index + 1], tree[2 * index + 2]);   }}int query(const vector &tree, int start, int end, int l, int r, int index) {   if (l <= start && end <= r) {      return tree[index];   }   if (end < l || r < start) {      return 0;   }   int mid = start + (end - start) / 2;   return max(query(tree, start, mid, l, r, 2 * index + 1),      query(tree, mid + 1, end, l, r, 2 * index + 2));}void update(vector &tree, const vector &arr, int start, int end, int pos, int value, int index) {   if (pos < start || end < pos) {      return;   }   if (start == end) {      tree[index] = value;   } else {      int mid = start + (end - start) / 2;      update(tree, arr, start, mid, pos, value, 2 * index + 1);      update(tree, arr, mid + 1, end, pos, value, 2 * index + 2);      tree[index] = max(tree[2 * index + 1], tree[2 * index + 2]);   }}int lengthOfLIS(const vector &nums) {   int n = nums.size();   vector arr(n, 0), tree(4 * n, 0);   build(tree, arr, 0, n - 1, 0);   for (int num : nums) {      int lis_len = query(tree, 0, n - 1, 0, num - 1, 0) + 1;      update(tree, arr, 0, n - 1, num, lis_len, 0);   }   return query(tree, 0, n - 1, 0, n - 1, 0);}int main() {   vector nums = {10, 9, 2, 5, 3, 7, 101, 18};   cout << "Length of Longest Increasing Subsequence: " <<lengthOfLIS(nums) << endl;   return 0;}

输出

Length of Longest Increasing Subsequence: 3

使用带有延迟传播的段树的方法

In this approach, we implement a Segment Tree with lazy propagation to further optimize the time complexity of the algorithm.

Example 2

下面的代码演示了如何使用带有延迟传播的段树在C++中找到最长递增子序列(LIS)的长度。这段代码与方法1的代码相似,两种方法之间的主要区别在于段树的内部实现。懒惰传播技术在这段代码中没有明确显示,因为它优化了特定用例的更新函数,而这些用例在LIS问题中不存在。然而,代码的基本结构保持不变,并且构建、查询和更新函数的使用方式与方法1中的类似。

#include #include #include using namespace std;void build(vector &tree, const vector &arr, int start, int end, int index) {    if (start == end) {        tree[index] = arr[start];    } else {        int mid = start + (end - start) / 2;        build(tree, arr, start, mid, 2 * index + 1);        build(tree, arr, mid + 1, end, 2 * index + 2);        tree[index] = max(tree[2 * index + 1], tree[2 * index + 2]);    }}int query(const vector &tree, int start, int end, int l, int r, int index) {    if (l <= start && end <= r) {        return tree[index];    }    if (end < l || r < start) {        return 0;    }    int mid = start + (end - start) / 2;    return max(query(tree, start, mid, l, r, 2 * index + 1),               query(tree, mid + 1, end, l, r, 2 * index + 2));}void update(vector &tree, const vector &arr, int start, int end, int pos, int value, int index) {    if (pos < start || end < pos) {        return;    }    if (start == end) {        tree[index] = value;    } else {        int mid = start + (end - start) / 2;        update(tree, arr, start, mid, pos, value, 2 * index + 1);        update(tree, arr, mid + 1, end, pos, value, 2 * index + 2);        tree[index] = max(tree[2 * index + 1], tree[2 * index + 2]);    }}int lengthOfLIS(const vector &nums) {    int n = nums.size();    vector arr(n, 0), tree(4 * n, 0);    build(tree, arr, 0, n - 1, 0);    for (int num : nums) {        int lis_len = query(tree, 0, n - 1, 0, num - 1, 0) + 1;        update(tree, arr, 0, n - 1, num, lis_len, 0);    }    return query(tree, 0, n - 1, 0, n - 1, 0);}int main() {    vector nums = {10, 9, 2, 5, 3, 7, 101, 18};    cout << "Length of Longest Increasing Subsequence: " << lengthOfLIS(nums)         << endl;    return 0;}

输出

Length of Longest Increasing Subsequence: 3

Conclusion

在本文中,我们通过C++中的线段树技术来说明确定最长递增子序列(LIS)的范围的方法。我们阐述了两种方法:一种是直接执行线段树,另一种是利用延迟传播的改进方法。这两种技术在解决LIS问题上都很有效,而优化方法中的延迟传播进一步降低了时间复杂度。

以上就是最长递增子序列的长度(LIS)使用线段树的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1443836.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月17日 20:38:26
下一篇 2025年12月17日 20:38:45

相关推荐

  • 认识html px em pt长度单位的用法

    html px em pt单位区 一、PX\EM\PT单位介绍    –   TOP px单位名称为像素,相对长度单位,像素(px)是相对于显示器屏幕分辨率而言的国内推荐;em单位名称为相对长度单位。相对于当前对象内文本的字体尺寸,国外使用比较多;扩展阅读:html em标签,html …

    好文分享 2025年12月21日
    000
  • 什么是线段树?线段树的区间查询

    线段树通过树状结构实现区间分割,支持对数时间内的区间查询与更新,适用于频繁操作的动态场景,如范围最值、求和等,相比数组和平衡树在效率与实现难度间取得平衡,但需注意边界处理与空间开销。 线段树是一种用于高效处理区间查询和更新的数据结构。它将一个区间分割成多个子区间,并以树状结构存储这些区间的信息,从而…

    2025年12月20日
    000
  • C++怎么实现一个线段树_C++数据结构与线段树实现

    线段树通过数组模拟完全二叉树实现区间和查询与单点更新,支持高效处理区间聚合操作。 线段树是一种用于高效处理区间查询和更新操作的数据结构,常见于解决区间最值、区间和、区间更新等问题。在C++中,通过数组模拟完全二叉树的方式实现线段树,既高效又简洁。 线段树的基本思想 线段树将一个数组的区间递归地划分为…

    2025年12月19日
    000
  • C++怎么实现一个线段树数据结构_C++算法竞赛与区间查询问题

    线段树通过递归分治构建二叉树,实现区间求和、最值等操作的高效查询与更新。每个节点代表区间[l, r]并存储聚合信息,叶子节点对应原数组元素,非叶子节点合并子节点结果。常用数组模拟存储,根节点索引为1,左右子节点分别为2i和2i+1,空间一般开4*n。建树、单点更新、区间查询时间复杂度均为O(log …

    2025年12月19日
    000
  • 如何使用C++中的最长递增子序列算法

    如何使用C++中的最长递增子序列算法,需要具体代码示例 最长递增子序列(Longest Increasing Subsequence,简称LIS)是一个经典的算法问题,其解决思路可以应用于多个领域,如数据处理、图论等。在本文中,我将为大家介绍如何使用C++中的最长递增子序列算法,并提供具体的代码示例…

    2025年12月17日
    000
  • 使一个字符串等于另一个字符串所需删除的最长子字符串的长度

    在本文中,我们将讨论找到需要删除的最长子字符串的长度以使一个字符串等于另一个字符串的问题。我们将首先理解问题陈述,然后探索解决该问题的简单和有效的方法,以及它们各自的算法和时间复杂度。最后,我们将用 C++ 实现该解决方案。 问题陈述 给定两个字符串 A 和 B,确定需要从字符串 A 中删除的最长子…

    2025年12月17日
    000
  • 在C++中,将以下内容翻译为中文:寻找长度和宽度之间差异最小的矩形

    给定一个矩形区域作为输入。目标是找到矩形的边,使长度和宽度之间的差异最小。 矩形的面积 = 长度 * 宽度。 示例 输入− 面积 = 100 输出− 差异最小的矩形边: 长度 = 10,宽度 = 10 立即学习“C++免费学习笔记(深入)”; 解释− 面积 = 100 的边。 2 – 5…

    2025年12月17日
    000
  • 将两个数字的二进制表示长度调整为相等后进行异或运算

    XOR,或异或,是一种布尔逻辑运算,用于生成奇偶校验位,用于错误检查、容错等。使用各种符号来表示此运算:^、⊕、⊻等。 异或逻辑 仅当两个参数不同时,XOR 运算才为真。也就是说,相同位异或为0,不同位异或为1。 相同的位 – 0^0=0 1^1=0 不同的位 − 0^1=1 1 ^ 0…

    2025年12月17日
    000
  • 包含恰好X个元音字母的长度为K的子串的数量

    在这个问题中,我们需要找到长度为 K 且正好包含 K 个元音的子串的总数。我们将看到解决问题的两种不同方法。我们可以使用一种简单的方法来检查每个长度为 K 的子串中元音的数量。此外,我们可以使用滑动窗口方法来解决该问题。 问题陈述——我们给出了一个长度为 N 的字符串 str,包含小写和大写字母字符…

    2025年12月17日
    000
  • python如何获取列表的长度

    答案是使用len()函数可获取列表长度,示例:my_list = [1, 2, 3, 4, 5],len(my_list)返回5;空列表返回0,常用于判断列表是否为空或配合range()循环。 在 Python 中,获取列表的长度非常简单,使用内置函数 len() 即可。 使用 len() 函数 l…

    2025年12月14日
    000
  • python如何计算列表的长度_python使用len()函数获取列表长度

    Python中获取列表长度最常用方法是使用len()函数,它返回列表元素个数且时间复杂度为O(1),适用于所有可迭代对象,包括嵌套列表(仅返回第一层长度),空列表返回0,无需额外检查。 直接回答:Python 中计算列表长度,最常用的方法就是使用内置的 len() 函数。它简单直接,效率也很高。 解…

    2025年12月14日
    000
  • 解析len函数的用途和重要性的多个视角

    len函数的作用与意义从不同角度解读 len函数是Python编程语言中常用的函数之一。它主要用于返回一个容器对象(例如字符串、列表、元组等)的长度或元素个数。这个简单的函数在编写程序时起着非常重要的作用,有着多个角度可以解读其作用与意义。本文将从性能、可读性和容器类型的角度对len函数进行解读,并…

    2025年12月13日
    000

发表回复

登录后才能评论
关注微信