我的直觉是从列表中选择前100个元素(比排序便宜得多,使用您最喜欢的QuickSelect变体).通过过滤器运行它们,产生n成功和100-n失败.如果n < 100然后通过100-n从列表的其余部分的顶部选择元素来重复:
k = 100
while (k > 0):
select top k from list and remove them
filter them, yielding n successes
k = k - n
Run Code Online (Sandbox Code Playgroud)
一切顺利,其运行时间与列表长度成正比,因为每个选择步骤都在该时间内运行,所需的选择步骤数取决于过滤器的成功率,而不是直接取决于列表的大小.
不过,我预计这会有一些不好的情况.如果几乎所有元素都没有通过过滤器,那么它比排序所有内容要慢得多,因为你最终会选择数千次.因此,如果它看起来很糟糕,你可能需要一些标准来挽救,然后再回到整个列表的排序.
它还存在这样的问题:它可能会在最后进行大量的小选择,因为如果过滤条件与排序标准无关,我们预计k会以指数方式衰减.所以你可以通过在每一步选择多于k个元素来改进它.比如说,k除以滤波器的预期成功率加上一个小常数.如果没有可用于预测它的领域知识,则基于过去表现的期望,以及通过实验选择的小常量来避免繁琐的大量步骤来找到最后几个元素.如果您在任何步骤中结束了更多通过过滤器的项目而不是您仍在寻找的项目(即n> k),那么从当前成功的一批中选择前k,您就完成了.
由于QuickSelect为您提供了顶级k而没有对这些k进行排序,因此如果您需要按顺序排在前100位,则需要进行最终的100个元素.