整数输入流中先前遇到的较小元素的计数

Count of previously smaller elements encountered in an input stream of integers?

本文关键字:元素 遇到 输入流 整数      更新时间:2023-10-16

给定一个从1到10^5(非重复)的数字输入流,我们需要能够在每个点上告诉之前遇到过多少比这个小的数字。

我尝试在c++中使用集合来维护已经遇到的元素,然后在集合上取当前数字的upper_bound。但是upper_bound给了我元素的迭代器,然后我必须再次遍历集合或者使用std::distance,它在时间上也是线性的。

为了更有效地完成这个任务,我可以维护一些其他的数据结构或遵循一些其他的算法吗?

EDIT:找到一个关于分域树的老问题,在这里很有帮助。顺便说一句,我现在已经解决了这个问题,使用段树从@doynax评论中获得提示。

如何使用二进制索引树来计算小于索引值的元素数量?

无论你使用的是哪种容器,最好将它们作为排序集输入,这样在任何时候我们都可以获得元素索引或迭代器,从而知道在它之前有多少元素。

您需要实现自己的二叉搜索树算法。每个节点应存储两个计数器,其中包含其子节点的总数。

插入二叉树需要O(log n)。在插入期间,该新元素的所有父元素的计数器都应该增加O(log n)

可从存储计数器O(log n)中导出小于新元素的元素个数。

总运行时间O(n log n) .

在每个步骤中保持表的排序。使用二分搜索。在每一点上,当你搜索输入流给你的数字时,二分查找会找到下一个最大的数,或者下一个最小的数。使用比较,您可以找到当前输入的索引,其索引将是小于当前输入的数字。该算法耗时O(n^2)

如果使用插入排序将每个数字存储到链表中会怎么样?然后,当找到新元素在列表中的位置时,可以计算比新元素小的元素的数量。

这取决于您是否想要使用std。在特定情况下std的某些部分是低效的。(例如,std::vector某些情况下可能被认为是低效的,因为发生了大量的动态分配。)这是一个具体情况具体分析的问题。

一种可能的解决方案是使用跳跃表(相对于链表),因为将元素插入跳跃表比插入数组更容易、更有效。

必须使用跳跃表方法,因此可以使用二分查找来插入每个新元素。(不能在普通链表中使用二分查找。)如果使用累加器跟踪长度,则返回较大元素的个数将像length-index一样简单。

使用这种方法的另一个可能的好处是,std::set.insert()在没有提示的情况下已经具有log(n)的效率,因此效率已经存在问题。