Algorithm 具有最长子序列长度查询的动态改变n长度序列的数据结构

Algorithm 具有最长子序列长度查询的动态改变n长度序列的数据结构,algorithm,data-structures,Algorithm,Data Structures,我需要设计一个数据结构来保存n长度的序列,方法如下: 递增()-返回最长递增子序列的长度 更改(i,x)将x添加到序列的第i个元素中 直觉上,这听起来像是某种区间树可以解决的问题。但我不知道该怎么想 我想知道如何使用这个事实,我们完全不需要知道这个子序列是什么样子,我们只需要它的长度 也许这是可以使用的东西,但我在这一点上几乎被卡住了。LIS可以用树来解决,但是还有另一个动态编程的实现,它比递归树更快。 这是C++中的一个简单实现。 class-LIS{ 私有向量seq; 公共LIS(向量_

我需要设计一个数据结构来保存
n
长度的序列,方法如下:

  • 递增()
    -返回最长递增子序列的长度
  • 更改(i,x)
    将x添加到序列的第i个元素中
直觉上,这听起来像是某种区间树可以解决的问题。但我不知道该怎么想

我想知道如何使用这个事实,我们完全不需要知道这个子序列是什么样子,我们只需要它的长度


也许这是可以使用的东西,但我在这一点上几乎被卡住了。

LIS可以用树来解决,但是还有另一个动态编程的实现,它比递归树更快。 这是C++中的一个简单实现。
class-LIS{
私有向量seq;
公共LIS(向量_-seq){seq=_-seq;}
公共整数增加(){
int i,j;
向量长度;
调整长度(seq.size());

对于(i=0;i我试图解释我的想法。它可能比实现区间树要简单一些,并且应该给出理想的复杂度-O(1)表示递增(),O(日志)表示更改(),其中S是序列计数(当然,在最坏的情况下可以减少到N)

首先,您需要原始数组。它需要在change()之后检查间隔的边界(我将使用单词interval作为序列的同义词)。让它成为A

第二步,您需要间隔的双向列表。此列表的元素应存储左边框和右边框。每个递增序列应作为此列表的单独元素显示,并且此间隔应按照A中显示的顺序依次显示。将此列表设为L。我们需要操作指针在元素上,所以,我不知道是否可以用标准容器在迭代器上实现

第三,您需要优先级队列来存储数组中所有间隔的长度。因此,递增()函数可以在O(1)时间内完成。但您还需要存储从L到查找间隔的节点指针。让此优先级队列为PQ。更正式地说,优先级队列包含对(间隔长度,指向列表节点的指针),仅按长度进行比较

第四,您需要树,它可以检索特定元素的间隔边界(或范围)。它可以简单地用std::map实现,其中key是树的左边界,所以在map::lower_bound的帮助下,您可以找到这个间隔。值应该将指向间隔的指针存储在L中。让这个映射为MP

下一件重要的事情-列表节点应该在优先级队列中存储相应元素的索引。并且,在没有连接到L节点的链接的情况下,您不应该使用优先级队列(在PQ上的每个交换操作都应该在L上更新相应的索引)

更改(i,x)操作可以如下所示:

  • 查找间隔,我用map定位的地方。->您可以在L中找到指向相应节点的指针。所以,您知道间隔的边界和长度
  • 试着理解动作需要做什么:什么都不做,分割间隔,粘合间隔
  • 在与PQ连接的列表和地图上执行此操作。如果需要拆分间隔,请将其从PQ中移除(这不是移除最大操作),然后向PQ添加两个新元素。类似的,如果需要粘合间隔,可以从PQ中移除一个,并将关键点增加到秒

  • 一个困难是,PQ应该支持删除任意元素(通过索引),因此您不能使用std::priority\u queue,但它并不像我想的那样难以实现。

    这只解决了连续间隔的问题。它不解决任意子序列。:-(

    对于间隔和
    O(log(n))
    更改,可以使用时间
    O(1)
    来实现这一点

    首先,我们需要为所有当前间隔创建一个堆,最大间隔位于堆的顶部。查找最长间隔只是查看堆的顶部的问题

    接下来,我们需要为每个
    n
    插槽提供一组信息

    value: Current value in this slot
    interval_start: Where the interval containing this point starts
    interval_end: Where the interval containing this point ends
    heap_index: Where to find this interval in the heap NOTE: Heap operations MUST maintain this!
    
    现在是一个聪明的技巧!我们总是存储每个插槽的值。但是我们只在索引可被2的最高幂整除的区间点存储区间的区间信息。任何区间总是只有一个这样的点,因此存储/修改这一点的工作非常少

    然后,为了找出数组中给定位置当前所处的间隔,我们必须查看所有以2的幂递增的相邻位置,直到找到最后一个具有我们的值的位置。例如,位置
    13
    的信息可以在
    0、8、12、13、14、16、32、64等任何位置中找到。
    (我们将取第一个区间,我们在列表中找到它,
    0,…,64,32,16,8,12,14,13
    )这是对
    O(log(n))
    列表的搜索,
    O(log(n))
    工作也是如此

    现在我们如何实现
    更改

  • 更新值
  • 弄清楚我们在哪个区间,是否在区间边界
  • 如果更改了间隔,请从堆中删除旧的间隔。(我们可以删除0、1或2)
  • 如果间隔发生变化,则将新的间隔插入堆中。(我们可以插入0、1或2)

  • 该更新非常复杂,但它是一个固定数量的
    O(log(n))
    操作,因此应该是
    O(log(n))

    这看起来不是最有效的解决方案。在理想的解决方案中,当您要求
    增加()
    时,您不会从scrat解决问题