鉴于数字输入流的范围从1到10 ^ 5(非重复),我们需要能够告诉每个点以前遇到过多少小于此的数字。
我尝试使用C ++中的set来维护已遇到的元素,然后在当前数字的集合上取upper_bound
。但是upper_bound
给了我元素的迭代器,然后我必须遍历集合或使用std::distance
,它再次是线性的。
我是否可以维护其他一些数据结构或遵循其他算法以更有效地完成此任务?
编辑:找到一个与fenwick树相关的旧问题,这在这里很有帮助。顺便说一下,我现在使用段树从@doynax评论中获取提示来解决这个问题。
答案 0 :(得分:1)
无论您使用哪个容器,最好将它们作为有序集输入,这样我们就可以在任何时候获取元素索引或迭代器以了解它之前有多少元素。
答案 1 :(得分:1)
保持每一步的表格排序。使用二进制搜索。在每个点上,当您搜索输入流刚刚给出的数字时,二进制搜索将找到下一个最大数字或下一个最小数字。使用比较,您可以找到当前输入的索引,其索引将是小于当前索引的数字。该算法需要O(n ^ 2)时间。
答案 2 :(得分:1)
您需要实现自己的二叉搜索树算法。每个节点应存储两个计数器,其子节点总数。
插入二叉树需要O(log n)
。在插入期间,该新元素的所有父元素的计数器应递增O(log n)
。
小于新元素的元素数量可以从存储的计数器O(log n)
中派生。
所以,总运行时间O(n log n)
。
答案 3 :(得分:0)
如果您使用插入排序将每个数字存储到链接列表中,该怎么办?然后,当您找到将其放在列表中的位置时,您可以计算少于新元素的元素数。
答案 4 :(得分:0)
这取决于您是否要使用std
。在某些情况中,std
的某些部分效率低下。 (例如,由于发生了动态分配的数量,在{em>某些情况下,std::vector
可能被认为效率低下。)这是一种个案的事情。
这里的一个可能的解决方案可能是使用跳过列表(相对于链接列表),因为将元素插入跳过列表比插入数组更容易,更有效。
您必须使用跳过列表方法,因此您可以使用二进制搜索来插入每个新元素。 (不能在普通链表上使用二进制搜索。)如果您使用累加器跟踪长度,则返回较大元素的数量就像length-index
一样简单。
使用此方法的另一个可能的好处是std::set.insert()
is log(n) efficient already without a hint,因此效率已经存在问题。