这里有两个整数集,比如A和B. 我们可以得到另一个集合C,其中每个元素都是A中元素a和B中元素b的总和。
例如,A = {1,2},B = {3,4},我们得到C = {4,5,6},其中4 = 1 + 3,5 = 1 + 4 = 2 + 3, 6 = 2 + 4
现在我想找出哪个数字是集合C中第k个最大的数字,例如5是上面例子中的第二大数字。
是否有有效的解决方案?
我知道成对求和排序是一个开放的问题,并且n ^ 2的时间界限较低。但由于只需要第k个最大数,我们可以从O(n)算法中学习未排序数组中的中位数。
感谢。
答案 0 :(得分:4)
如果k非常接近1或N,任何懒惰地生成排序和的算法都可以直接运行,直到第k个或第N个项目弹出。
特别是,我正在考虑对以下空间进行最佳搜索:(a,b)表示来自A的第一个列表的项目,从B添加到b,第二个。
保持最佳=最低优先级队列对(a,b),成本(a,b)= A [a] + B [b]。
从优先级队列中的(1,1)开始,这是最小值。
Repeat until k items popped:
pop the top (a,b)
if a<|A|, push (a+1,b)
if a=1 and b<|B|, push (a,b+1)
这为您提供了锯齿梳连接,使您无需标记阵列中访问过的每个(a,b)。请注意,成本(a + 1,b)&gt; =成本(a,b)和成本(a,b + 1)&gt; =成本(a,b),因为A和B已排序。
这是一张梳子的图片,显示上面的后继生成规则(从左上角开始; a是水平方向):
|-------
|-------
|-------
这是(最多)所有| A | * | B |的最佳探索元组及其总和。
请注意,在弹出k之前推送的最多可能项目是2 * k,因为每个项目都有1或2个后继项。这是一个可能的队列状态,其中推入队列的项目标记为*
:
|--*----
|-*-----
*-------
*
边界上方和左侧的所有内容都已弹出。
对于N-k<k
情况,做同样的事情,但反向优先级队列顺序和探索顺序(或者,只是否定和反转值,得到(Nk)至少,然后否定并返回答案)
另请参阅:成对总和的排序列表on SO或Open problems project。
答案 1 :(得分:4)
排序数组A&amp; B:O(mlogm + nlogn) 应用修改形式的算法合并2个排序数组:O(m + n) 即在每个点,你将这两个元素相加。 当你在C中得到(m + n-k + 1)个元素时,停止合并。该元素基本上是第k个。 例如。 {1,2}&amp; {3,4}:排序 C: {1 + 3,(1 + 4)|(2 + 3),2 + 4}
答案 2 :(得分:0)
嗯,O(n)将是一个下限(虽然可能不紧),否则你可以运行O(n)算法n次以获得O(n ^ 2)中的排序列表。
你能否假设这两组是排序的(你按照上面的排序顺序呈现)?如果是这样的话,你可能会得到一些平均情况,通过做一个“早出”,从最后一对元素开始,等等。但只是预感。