例如,我们有一个排序的数组
30,20,10,-1,-2,-15
现在,我们要计算其部分和(对于每个数字,您可以选择将其相加或不相加),并按降序获取前n个最大的数字(例如,前11个)。
60 = 30 + 20 + 10
59 = 30 + 20 + 10 -1
58 = 30 + 20 + 10 -2
57 = 30 + 20 + 10 -1 -2
50 = 30 + 20
49 = 30 + 20 -1
48 = 30 + 20 -2
47 = 30 + 20 -1 -2
45 = 30 + 20 + 10 -15
44 = 30 + 20 + 10 -1 -15
43 = 30 + 20 + 10 -2 -15
一个朴素的解决方案是计算所有组合(对于上面的示例,有2 ^ 6 = 64个组合),以降序对其进行排序,然后获取其中的前11个数字:
60、59、58、57、50、49、48、47、45、44、43,,42、40、39、38、37、35、34、33、32, 30、30、29、29、28、28、27、27、25、24、23、22、20、19、18、17、15、15、14、14、13、13、12、12、10, 9、8、7、5、4、3、2、0,-1,-2,-3,-5,-6,-7,-8,-15,-16,-17,-18 >
但是,当数组的长度很大时,计算所有组合是不可行的。因此问题是,是否可以迭代方式获取前n个最大的部分和。一次取一个号码?
要明确一点,最终目标是,假设数组是全局数组,我想要一个函数f()
:通过迭代调用f()
,它将以降序返回最大的部分和。
调用f(),返回60
再次调用f(),返回59
再次调用f(),返回58
......
答案 0 :(得分:1)
http://www.vldb.org/pvldb/vol4/p1028-golenberg.pdf中描述了一种针对劳斯莱斯·穆尔蒂(Lawler-Murty)的问题的非常通用的程序。如果您不希望所有答案(也许仅仅是前十名),或者不足以耗尽人类在搜索结果中的耐心,则最实用。
这是尝试针对您的问题提供更简单的版本。
请考虑由位向量定义的每个答案,其中0表示采用较低的选项,而1表示采用较高的选项。也就是说:如果数字为正,则1表示选择,0表示未选择。如果为负,则1表示未选择,0表示已选择。因此111111表示30 + 20 + 10(+ 0 + 0 + 0),而000000表示(0 + 0 + 0)-1-2-15。 111111将永远是最高答案。
将这些向量想像成一棵树,顶部是111111。通过设置最左边的0位,可以找到任何0位向量的父级。这意味着父母总是比其子女拥有更高的价值。节点具有可变数量的子节点,其中111111的子节点最多:011111、101111、110111、111011、111101和111110。枚举父节点的所有子节点的一种方法是将父节点中的所有1都作为父节点。他们的左边没有0位,并依次清除它们。
树的顶部是111111。将其放在优先级队列中,该优先级队列由每个向量计算出的总和排序。现在,反复将金额最高的项目从队列中取出,打印出来,然后将其所有子项放入队列中。
这将以不递增的顺序打印出所有答案。最大值的子级不高于父级,因此优先级队列中的最大值永远不会增加。每个可能的答案都有一连串的父母带回最多111111(设置最左边的位),因此您找到了每个可能的答案。