【问题标题】:Group/form chains of all next greater elements所有下一个更大元素的组/形成链
【发布时间】:2020-07-10 11:34:25
【问题描述】:

从当前索引的值开始的所有下一个更大元素的组/表单链 (合并到任何现有链中)

例如:考虑成堆的一些物体 ----------

A[1 3 2 4 5 1 2 3 7]


从第一个索引开始 A[0] = 1


下一个大于 1 => 3


下一个大于 3 => 4


下一个大于 4 => 5


下一个大于 5 => 7


所以我们得到了我们的第一个链 [1 3 4 5 7]


现在对于第二组,[1 3] 已经从 A[2] 开始(基于 0)


A[2] = 2,下一个大于 2 =>4


4 已经包含了,所以很明显它将跟随它进行其余的交互,所以现在它在值 4 处合并到 chain1,


所以 G2 将有 [2 4]


我希望这一切都被表示为一棵树,如图所示 this

我尝试使用 O(N*N) 的朴素方式, 我尝试使用 库存跨度问题 进行改进,但我不知道如何在 ma​​x 时实现它 O(N log N)

【问题讨论】:

  • 下一个更大的元素是什么意思?
  • 对应图,我猜G3应该是[1 2 3 7]
  • 是的,应该是[1 2 3 7]
  • @CanBayar next 更大的意思是,我们只需要向上移动(即,如果有的话,在当前索引之后移动到更大的值)。
  • 你提到了堆栈跨度问题,可以在 O(n logn) 内解决。我不明白这里与你的问题的关系。也许你只是想,对于给定的索引i,找到索引j,使得j-i 是最小值并且a[j] > a[i]

标签: arrays algorithm data-structures


【解决方案1】:

我将说明如何做到这一点,但不会给你代码。

你从一个列表开始:

1 3 2 4 5 1 2 3 7

这里添加了职位,所以我们可以更轻松地讨论它。

1 3 2 4 5 1 2 3 7
0 1 2 3 4 5 6 7 8

我们想要的是一个新的“下一个最大元素的位置”数组,如下所示:

1 3 2 4 5 1 2 3 7
0 1 2 3 4 5 6 7 8
1 3 3 4 8 6 7 8 x

最后一个数组包含构建所需树所需的所有信息。挑战在于如何有效地生成该数组。

我们将通过从数组的后面向后走来生成它。在每个步骤中回答O(log(n)) 中的必要问题。我将描述的数据结构是Skip List 的一个变体。它会告诉我们,在按值排序的搜索中,可以找到大于该值的任何东西的最低索引。我们所做的是在时间O(log(n)) 中搜索我们的值,然后插入可以在时间O(log(n)) 中找到该值的事实。

如那篇文章所述,跳过列表是数据的链接列表。然后是一个较高的数据链表,总结了较低数据的一些内容。与“跳过”。然后是一个更高的链表。每个数据点都达到一个高度。一半的点位于高度 0(仅底部列表),一半位于高度 1,四分之一位于高度 2,依此类推。整个数据结构最终大小为n + n/2 + n/4 + ...,大小约为2n。所有操作平均在log(n) 个操作中完成。

我将在没有必要的指针的情况下绘制它来遍历数据结构,每一层都是一行。通过right/left/down/up 可以在视觉上执行的操作需要程序中的指针。我们的实际节点总是看起来像(value, first index met or exceeded)。 (您会看到节点值可能是陈旧的,但这没关系。)

现在,在跳过列表中,您通常会随机分配节点的高度。平均而言,这是可行的。但我将使用 2 的最高幂,将值除以我的身高。对于本示例,这实现了良好的高度分布,而没有令人困惑的随机选择。

诀窍在于,当我们读取跳过列表时,我们从顶部开始,然后向右移动,然后向下移动,直到找到大于或等于我们正在寻找的值。然后我们向左和向下移动(向左是该值仍然大于我们想要的值,否则向下)并沿着我们找到的第二条路径获取最小索引。当我们插入时,我们总是尝试向上移动,然后向左移动,沿着这条轨迹记录新插入的索引。

现在为了使操作的踪迹清晰,我将在我的数据结构中添加在此操作期间采用的路径。这意味着以下操作:

  • l正在寻找更高的值来开始搜索下一个索引。
  • s寻找下一个索引。 (我一找到这个就切换,所以如果我首先看到的是search 的一部分,可能根本就没有l。)
  • inserting 一个新节点(因为这是一个二维链表结构,你也有我没有显示的邻居指针的更新)。这发生在最后一个s 之前,然后直接上升。但前提是价值对我们来说是新的。
  • updating 关于节点的一些事情。它们从最后一个search 或insert 的左侧开始,然后尝试向上移动然后向左移动。如果这是一个新的最小值,则不会更新。

现在请记住,我们从以下开始:

1 3 2 4 5 1 2 3 7
0 1 2 3 4 5 6 7 8

我们想要在我们的跳过列表中的第一个事实是值7 可以在位置8 找到。这个事实的高度为 0,所以我们的跳过列表如下所示:

next: [x]
skip: (7,8)i

接下来我们发现3 可以在7 位置找到。搜索下一个最高值是微不足道的。我们在级别 0 插入另一个事实并得到以下结果:

next: [8,x]
skip: (3,7)i  (7,8)s

接下来可以在位置6 找到值2。这引入了一个新的水平。

next: [6,7,8,x]
skip: (2,6)i
      (2,6)i  (3,7)s  (7,8)

接下来可以在位置5找到值1

next: [5,6,7,8,x]
skip:         (2,6)s
      (1,5)i  (2,6)s  (3,7)  (7,8)

现在值5 出现在位置4。由于这是第一个复杂的,字母表明我们 looked 在顶部的 (2,6) 处开始搜索,然后向下,对,对。然后我们s只搜索(7,8)。然后我们insert 和下面的update 向左、向左、向上移动。请注意,左下角的陈旧(1,5) 永远不会给我们一个错误的结论,因为任何命中它的搜索都会首先找到(2,4),因此我们知道使用4 的索引而不是陈旧的5 .

next: [8,5,6,7,8,x]
skip:         (2,4)lu
      (1,5)   (2,4)lu (3,4)lu (5,4)i  (7,8)s

现在4 可以在3 位置找到。这次的阅读往下,左,左找到起始(5,4)。我们的插入返回一个然后直接向上移动以创建一个新的水平。我们有很多没有接触过的陈旧数据。

next: [4,8,5,6,7,8,x]
skip:                         (4,3)i
              (2,4)l          (4,3)i
      (1,5)   (2,4)l  (3,4)l  (4,3)i  (5,4)s  (7,8)

接下来,2 可以在位置2 找到。这些记录存在,所以这是update。

next: [3,4,8,5,6,7,8,x]
skip:                         (4,3)s
              (2,2)u          (4,3)s
      (1,5)   (2,2)u  (3,4)s  (4,3)s  (5,4)   (7,8)

我们快到了! 3 现在可以在位置1 找到。我们的搜索直接进行了。然后我们找到根索引,更新它然后向左,向上。

next: [3,3,4,8,5,6,7,8,x]
skip:                         (4,3)s
              (2,1)u          (4,3)s
      (1,5)   (2,1)u  (3,1)i  (4,3)s (5,4)   (7,8)

现在我们向下、向左、向下、向左搜索最后一条记录。为了完整起见,我将更新数据结构以包含它,尽管我们永远不会再看。

next: [1,3,3,4,8,5,6,7,8,x]
skip:                         (4,3)s
              (2,1)           (4,3)s
      (1,0)u  (2,1)s  (3,1)s  (4,3)s   (5,4)   (7,8)

并且跳过列表的最终状态表示至少1的第一个值在0,至少23的第一个值在1,第一个值在至少43,至少5 的第一个值在4。并且至少7 的第一个值位于8

【讨论】:

  • 谢谢!为了你的努力,在最后的数组中,我想要所有这样的链,你的解释似乎是生成一个这样的链,它也可以通过维护一堆下一个更大的元素来生成,geeksforgeeks.org/next-greater-element
  • 对于上述内容,最终答案显然将包含所有索引, [0, 1, 3, 4, 5 , 8 ] [2, 4 -> 在索引 4 处合并到 First ] [6 ,7 , 8 -> 在索引 8 处合并到第一个]
猜你喜欢
  • 2019-11-29
  • 2020-02-16
  • 1970-01-01
  • 2016-03-23
  • 1970-01-01
  • 1970-01-01
  • 2017-05-11
  • 2014-07-28
  • 1970-01-01
相关资源
最近更新 更多