我在面试中被问到上述问题,面试官非常肯定答案。但我不确定。有人能帮我一下吗?
答案 0 :(得分:2)
不确定。明显的强力方法只是一个大的查找表,每个可能的输入数值都有一个条目。如果数字非常大,这不太实用,但仍足以证明它是可能的。
编辑:已经提出这个概念完全是胡说八道,基本上任何算法都可以这样说。
在有限的程度上,这是一个公平的陈述 - 但是限制是如此严重,以至于对于大多数算法而言,它仍然毫无意义。
我的原始观点(至少和我记得的一样)是人口计数与许多其他操作相似,例如加法和减法,我们通常认为是O(1)。
在硬件级别,单周期POPCNT
指令的电路可能比单周期ADD
指令更容易。仅举一个例子,对于任何实际大小的数据字,我们可以并行使用4位块上的表查找,然后将这些块的结果加在一起。即使使用相当不太可能的最坏情况假设(例如,每个表的单独存储),这仍然是 easy 在现代CPU中实现 - 事实上,它至少可能是比上面提到的单循环加法或减法更简单。
这与许多其他算法形成鲜明对比。举一个明显的例子,让我们考虑排序。对于大多数人可以想象的最微不足道的类型 - 2个项目,每个8位,我们已经在64千字节的查找表中以获得恒定的复杂性。 Long 在我们甚至可以做一个相当简单的排序(例如,100个项目)之前,我们需要一个包含远的数据项的查找表,而不是宇宙中的原子。< / p>
从相反的方向看,它确实在某些时候,基本上没有就是O(1)了。让我们考虑一下最简单的操作。对于N位CPU,按位OR
通常并行实现为一组N OR
个门。与添加不同,一位与另一位之间没有交互,因此对于任何实际大小的CPU,这都易于在单个指令中执行。
尽管如此,如果我指定一个逐位OR
,其中每个操作数是100 petabits,那么甚至没有任何接近实际工作方式的复杂性。使用通常的并行OR
门方法,我们最终得到了300个价值的输入和输出线 - 一个完全相形见绌的数字甚至是引脚数量最大的CPU。
在合理的硬件上,在100 petabit操作数上执行按位OR
需要一段时间(更不用说相当多的硬盘空间)。如果我们将其增加到200 petabit操作数,则时间可能(大约)加倍 - 因此从这个角度来看,它是O(N)操作。显然,对于另一个&#34;琐碎的&#34;同样的情况也是如此。加法,减法,逐位AND
,逐位XOR
等操作。
尽管如此,除非你有非常特定的指示说你将要处理完全巨大的操作数,否则你通常会将这些操作中的每一个视为常数复杂的操作。从这些术语来看,POPCNT指令一方面位于逐位AND
/ OR
/ XOR
之间,另一方面位于加法/减法之间,就难度而言在固定的时间内执行。
<子> 1。您可能想知道在执行其他操作后它实际包含add
时,它可能比add
更简单。如果是这样的话,那就是一个很好的问题。
答案是,因为它只需要一个更小的加法器。例如,64位CPU需要一个半加器和63个全加器。在简单的实现中,您按位执行加法 - 即,将一个操作数的第0位添加到另一个操作数的第0位。这会产生一个输出位和一个进位。该进位成为下一对位的加法输入。有一些技巧可以在某种程度上并行化,但野兽的性质(可以这么说)是位串行的。
使用POPCNT指令,我们在执行单个表查找后添加了一个,但是我们的结果仅限于输入字的大小。给定相同大小的输入(64位),我们的最终结果不能大于64.这意味着我们只需要一个6位加法器而不是64位加法器。
因为,如上所述,加法基本上是位串行的,这意味着POPCNT
指令末尾的加法基本上比正常情况下批次更快加。具体而言,它是操作数大小的对数,而简单的加法在操作数大小上大致是线性的。
答案 1 :(得分:1)
如果位大小是固定的(例如32位或64位机器的自然字大小),您可以迭代这些位并在O(1)时间内直接计数(尽管有更快的方法可以做它)。对于任意精度数字(BigInt等),答案必须为否。
答案 2 :(得分:1)
有些处理器可以在一条指令中完成,显然对于有限大小的整数。查看POPCNT助记符以获取更多详细信息。
对于无限大小的整数,显然你需要读取整个输入,因此下限是O(n)。
面试官可能意味着数字技巧(第一个Google结果如下):http://www.gamedev.net/topic/547102-bit-counting-trick---new-to-me/