我有一个问题,我想确保我是否最有效地做到这一点。我有一个大小为N的浮点值数组A.值都在0和1之间。
我必须找到前k个值,它们可以是A中最多三个数的乘积。所以,top-k列表可以 有来自A的个别数字,两个数字的乘积或来自A的三个数字的乘积。
所以,这就是我现在正在做的事情。我可以在O(Nlogk)时间内以令人憎恶的顺序获得前k个数字。然后我创建一个 max-heap并使用最大值3的最佳值初始化它,即如果我将k值的排序数组(降序)表示为B 以及该数组中索引的数字,我插入了索引(0),(0,1)和(0,1,2)的数字。接下来,我在堆上执行提取 每当我提取尺寸z(z数的乘积)值时,我将其替换为下一个可能的尺寸z数的集合,即 如果假设(2,4)被提取,我可以用(3,4)和(2,5)替换它。并提取k次以获得结果。
如果有的话,需要更好的想法。 谢谢大家。
答案 0 :(得分:2)
如果我理解正确,你需要找到k可以通过将列表中的1,2或3个元素相乘得到的最高数字,并且所有值都是0到1之间的浮点数。
很明显,您只需要考虑列表中的k个最高数字。其余的可以立即丢弃。您可以使用您的O(n log k)算法来获取它们,再次按排序顺序(我假设您的列表未预先排序)。为了简化问题,您现在可以采用它们的对数并尝试最大化数字的总和,而不是最大化产品的原始问题。这可能会加速。
现在(考虑对数表示),你的所有数字都是负数,因此将更多数字加在一起只会产生越来越多的负数。
我们叫k最高的数字A1 ... Ak。我们现在可以进一步减少问题,假设还存在数字A0,它在日志表示中的值为0,在原始表示中的值为1;然后问题是枚举第一个k 3元组({A0,...,Ak}中的x,y,z),约束为x≥y≥z且z <1。 A0。让我们用[i,j,n]表示3元组,并用S [i,j,n]表示该元组中元素的总和。要报告的第一个元素显然是[0,0,1],即,它在原始问题公式中对应于列表中的单例#1值。
我们在原始配方中使用max-heap;我们将三元组推到堆中,使用它们的总和(S [...])作为排序键。该算法首先将[0,0,0]推入堆中。然后:
answer = []
for m in 0 .. k:
top = heap.pop()
answer.append(sum(top))
(i,j,n) = top # explode the tuple
if (n < k - 1):
heap.push((i,j,n+1))
if (j == n):
heap.push((i,j+1,j+1))
if (i == j):
heap.push((i+1,i+1,i+1))
最后,answer包含k + 1个元素,其中第一个元素是[0,0,0],必须将其丢弃。
设为-1,-3,-8,-9。然后算法继续这样:
Heap
Top Rest (shown in order)
[ 0, 0, 0] |
[ 0, 0,-1] | [ 0,-1,-1] [-1,-1,-1]
[ 0,-1,-1] | [-1,-1,-1] [ 0,-1,-3] [ 0,-3,-3]
[-1,-1,-1] | [-1,-1,-2] [ 0,-1,-3] [-1,-2,-2] [-2,-2,-2] [ 0,-3,-3]
[-1,-1,-2] | [ 0,-1,-3] [-1,-1,-3] [-1,-2,-2] [-2,-2,-2] [ 0,-3,-3]
[ 0,-1,-3] | [-1,-1,-3] [ 0,-1,-4] [-1,-2,-2] [-2,-2,-2] [ 0,-3,-3]
[-1,-1,-3] | [ 0,-1,-4] [-1,-1,-4] [-1,-2,-2] [-2,-2,-2] [ 0,-3,-3]
[ 0,-1,-4] | [-1,-2,-2] [-1,-1,-4] [ 0,-1,-5] [-2,-2,-2] [ 0,-3,-3]
...
etc.
这个算法的优点是它不会枚举重复项,堆大小为O(k);要知道为什么,请注意算法会在每次迭代时添加堆上元素的最大值(通常更少),因此在k次迭代后,堆中的元素数不能超过2k。
这给出了运行时间O(n log k + k log k)= O((n + k)log k)。
答案 1 :(得分:1)
我当然看到你可以进行优化。
Let M be the highest number from A.
Let M2 be M * M.
Let setMM2 consist of all x from A such that M2 < x < M
If size(setMM2) >= k,
then your top-k consist of the highest k elements.
Else
all x in setMM2 are in your top-k and your search becomes smaller
您可以使用max(secondHighestNumber ^ 2,M ^ 3)重复此方法并概括算法。
答案 2 :(得分:0)
kNSince数字从0到1,你使用的数字越多,得到的数字就越大,问题就是大k,例如k = N ^ 2
首先尝试使用单个数字,然后在堆中推送。 O(N *日志(k))的
比从堆中使用这个数字并制作另一个堆B whit 2 number =&gt; O(k * log(k))最差,但如果你在k> N
的情况下对数字进行排序,你可以做一些加速然后你有堆2个数字和那些产品并尝试从堆B中制作第3个堆C,就像你为B做的那样,但是从更大的堆中。
我认为这会产生一个O(k * log(k))