如何权衡假币算法

时间:2017-03-21 22:23:43

标签: c++ arrays algorithm math bit-manipulation

我正在尝试为假币问题开发C ++代码。我使用的是一个长度为1s且随机为0的二进制数组来表示假硬币。当我将数组分成两半来比较重量时,我该如何确定每一侧的重量?

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

有没有办法在恒定时间内确定每个阵列的重量?

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

2 个答案:

答案 0 :(得分:0)

作为一名学生,我会坚持这一点,因为你计算每个一半中的1的数量,并且你正在有效地使用这种方法:

  

减小而治之

因此,您实际上正在权衡O(log 2 n)次,这使得算法处于次线性状态。

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

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

如果您想要使用某些代码,可以使用提供std::bitsetcount(),它返回位集中的1的数量。

答案 1 :(得分:0)

  

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

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

所以其他答案和评论建议你需要亚线性次数称重硬币,我倾向于同意这一点。

如果您仍然希望更快地执行比较(即范围和),则会有一个名为Fenwick tree的数据结构,它允许您以对数时间计算子范围和,但仍需要线性时间进行构造。但请注意,我认为将它用于您的任务在复杂性方面(它可能比您当前的级别更高级)和性能奖励(仅在您将要使用它时才有意义)许多range查询在您的阵列上运行,您将更改您的数组)。

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