如何在假硬币算法中称重

How to Weigh in Fake Coin Algorithm

本文关键字:算法 硬币      更新时间:2023-10-16

我正在尝试为假币问题开发C++代码。我正在使用一个二进制数组 n 长,填充 1 和一个随机 0 来表示假币。当我将数组分成两半以比较权重时,如何确定每条边的权重?

我可以很容易地计算每个数组中的 1 的数量,但这将是一个线性运行时间。整体算法应该是亚线性的。

有没有办法确定每个数组在恒定时间内的权重?

披露:这是一项学校作业,所以希望你能在不给出完整答案的情况下给出提示。

作为一名学生,我会坚持这一点,因为您每半数1 的数量,并且您有效地使用了这种方法:

减少和征服

因此,您实际上是在称量 O(log2n) 次,这使得算法成为亚线性。

我的观点是,优化算法的是您正在执行的称重次数及其有效空间(一半与总数)。

在此 CS 会话中阅读更多内容,建议您在 3 时拆分,您可以做得更好并达到 O(log3n)。但是,如果您是新手,那么现在分成两半就可以了!=)


如果你想玩一些代码,你可以使用 std::bitset,它提供 count(),它返回位集中的 1 个数。

我可以很容易地计算每个数组中的 1 的数量,但这将是一个线性运行时间。整体算法应该是亚线性的。

我想你在这里弄错了。整个算法不可能是亚线性的,很容易理解为什么:要至少读取每个硬币,你需要线性时间,因为硬币数量显然是线性数量的硬币。很明显,如果不至少阅读一次每枚硬币,就无法找到假硬币。(更严格地说,您需要阅读所有硬币,但至少一次,但这仍然是线性的。

因此,其他答案和评论表明,您需要称硬币次线性次数,我倾向于同意这一点。

如果您仍然想更快地进行比较(即范围内的总和),有一种称为 Fenwick 树的数据结构,它允许您以对数时间计算子范围总和,但仍需要线性时间来构建。但是请注意,我认为将其用于您的任务在复杂性(它可能比您当前的级别更高级)和性能奖励方面都是矫枉过正(仅当您要在阵列上运行许多range查询并且您将要更改数组时才有意义)。

另请注意,维基文章的第二段提出了一个简单的算法,它只需要线性时间进行初始化,然后在恒定时间内计算前缀和(从而计算范围和):只需再创建一个带有硬币前缀和的数组(或者如果您不再需要它,甚至可以就地更新原始数组)。显然RangeSum(a,b) = PrefixSum(b) - PrefixSum(a-1)(其中PrefixSum(-1)为 0)。如果你想炫耀,实现这个可能是有意义的,但就 Big-O 而言,仍然没有性能奖励。