如何在假币算法中称重
Posted
技术标签:
【中文标题】如何在假币算法中称重【英文标题】:How to Weigh in Fake Coin Algorithm 【发布时间】:2017-03-21 22:23:43 【问题描述】:我正在尝试为假币问题开发 C++ 代码。我正在使用一个长满 1 和一个随机 0 的二进制数组 n 来表示假硬币。当我将数组分成两半来比较权重时,如何确定每一边的权重?
我可以很容易地计算每个数组中 1 的数量,但这将是一个线性运行时间。整体算法应该是次线性的。
有没有办法在常数时间内确定每个数组的权重?
披露:这是一项学校作业,因此希望您可以在不给出完整答案的情况下给出提示。
【问题讨论】:
这更像是一个数学问题而不是一个软件问题。最好在数学 QA 处提问。 geeksforgeeks.org/decision-trees-fake-coin-puzzle 这解释了你的问题。看起来最佳解决方案是 log3(N),它是次线性的 你有错误的数据结构。您的数据结构应该有一个秘密编号 - 假币的 id,仅此而已。然后您可以回答“coin_set1
比coin_set2
重?”这样的问题。在 O(1) 中。
【参考方案1】:
作为一名学生,我会坚持这一点,因为您计算每 一半 中 1 的数量,并且您正在有效地使用这种方法:
减少和征服
因此,您实际上是在称重 O(log2 n) 次,这使得算法是次线性的。
我的观点是,优化算法的是您正在执行的称量次数及其有效空间(一半与总数)。
阅读此 CS session 中的更多信息,其中建议如果您在 3 处拆分,您可以做得更好并达到 O(log3 n)。但是,如果您对此不熟悉,那么现在分成两半就可以了! =)
如果你想玩弄一些代码,你可以使用std::bitset,它提供了count(),它返回位集中1的数量。
【讨论】:
【参考方案2】:我可以很容易地计算每个数组中 1 的数量,但这将是线性运行时间。整体算法应该是次线性的。
我认为你在这里弄错了。 整个算法不可能可能是次线性的,原因很容易理解:要读取每个硬币至少需要线性时间,因为显然有线性数量的硬币的数量。很明显,如果不至少阅读每枚硬币一次,您就无法找到假硬币。 (更严格地说,您需要阅读所有硬币,除了一个至少一次,但这仍然是线性的。)
因此,其他答案和 cmets 的建议是,您需要称重硬币的次线性次数,我倾向于同意这一点。
如果您仍想更快地执行比较(即对范围求和),则有一个名为 Fenwick tree 的数据结构,它允许您以对数时间计算子范围和,但仍需要线性时间来构建。但是请注意,我认为将它用于您的任务在复杂性(它可能比您当前的水平更高级)和性能奖励(只有在您将要拥有许多range
查询在您的阵列上运行并且您将更改您的阵列)。
还请注意,wiki 文章的第二段建议了一种简单的算法,该算法只需要线性时间进行初始化,然后在恒定时间内计算前缀和(以及范围和):只需再创建一个前缀和为的数组您的硬币(如果您不再需要它,甚至可以就地更新原始硬币)。显然RangeSum(a,b) = PrefixSum(b) - PrefixSum(a-1)
(其中PrefixSum(-1)
为0)。如果你想炫耀,实现这个可能是有意义的,但在 Big-O 方面仍然没有性能奖励。
【讨论】:
以上是关于如何在假币算法中称重的主要内容,如果未能解决你的问题,请参考以下文章