二次复杂度不好,但可以改进。 为此,我们将构建 线段树 为权重总和。 将获得深度为 lg N 的树,在其叶子中将有副本权重,在其余节点中将有部分和,直到树根处的所有权重之和。 接下来,我们生成一个从 0 到所有权重之和的随机数,找到第 i 个副本,将其从树中删除,然后重复该过程以找到剩余的副本。 使用该算法,构建树的复杂度为 O(N),找到第 i 个副本并将其从树中删除的复杂度为 O(lg N),选择 K 个副本的复杂度为 O(N + K lg N) ~ O(N lg N) 。
线性对数复杂度比二次复杂度更好,尤其是对于较大的 K。
就是这个算法 在代码中实现 项目中的 ClusterClient 库“东方”。 (其中,树的构建时间为 O(N lg N),但这并不影响算法的最终复杂度。)
任务 2. 斑马
有必要提出一种算法,通过任意非索引字段对内存中的文档进行有效排序:
您的团队的任务是开发分片内存文档数据库。 常见的工作负载是从大小为 M(通常 N < 100 << M)的集合中选择按任意(非索引)数字字段排序的前 N 个文档。 稍微不太常见的工作负载是在跳过前 S 个文档(S ~ N)后选择前 N 个。
提出一种算法来有效地执行此类查询。 在平均情况和最坏情况下使用大 O 表示法估计其计算复杂度。
解决方案分析(视频)
34:50开始,仅6分钟:
解决方案分析(文字)
表面解决方案:对所有文档进行排序(例如 快速排序),然后取N+S个文档。 在这种情况下,排序的复杂度平均为 O(M lg M),最坏为 O(M2)。
显然,对所有 M 个文档进行排序,然后只取出其中的一小部分是低效的。 为了不对所有文档进行排序,适合使用一种算法 快速选择,这将选择 N + S 个所需文档(它们可以通过任何算法排序)。 在这种情况下,平均复杂度将降低到 O(M),而最坏情况将保持不变。