棘手的算法问题[重复]

Posted

技术标签:

【中文标题】棘手的算法问题[重复]【英文标题】:Tricky algorithm question [duplicate] 【发布时间】:2011-05-01 17:53:36 【问题描述】:

可能重复:Quickest way to find missing number in an array of numbers

输入:未排序数组 A[1,..,n] 包含范围 0,..,n 中除一个整数之外的所有整数

问题是在 O(n) 时间内确定丢失的整数。 A 的每个元素是 以二进制表示,唯一可用的操作是函数 bit(i, j),它 返回 A[i] 的第 j 位的值,并花费常数时间。

有什么想法吗?我认为某种分而治之的算法是合适的,但我想不出我到底应该做什么。提前致谢!

【问题讨论】:

如果 bit(i,j) 是唯一可用的操作,您建议如何实现分治算法? @A. Rex:你链接的可能的骗子对指令没有相同的限制,所以我认为它不一定是骗子。 这不是重复的。在这个问题中,您只能读取输入 A 的 n log n 位中的 O(n)。如果这是唯一的约束(即,如果除了 bit(i, j) 之外的操作)是免费的,那么您仍然可以解决它,使用分治算法,有点:算法的注释大小描述是计算偶数和奇数的数量,检查哪个计数与您从 0 得到的不匹配... n,并在丢弃最低位后递归输入的那一半。 这不是 ***.com/questions/2113795 的副本,正如 Reid 解释的那样,paxdiablo 的回答是错误的。 Reid 的算法是 O(n),如果您在计数时保留一个列表,其中列出了每一半中的元素。 【参考方案1】:

1n 之间的数字之和是一个数学属性,其中 nn(n+1)/2。你可以看到10

  1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
= (1+10) + (2+9) + (3+8) +(4+7) + (5+6)
= 11 + 11 + 11 + 11 + 11
= 55

因此,通过扩展,是从 0n 的数字的总和,因为您只是将 0 添加到它。所以你要做的就是将所有数字相加并保持计数,然后使用该公式找出缺少的数字。

所以,类似:

count = 0
sum = 0
foreach num in list:
    sum = sum + num
    count = count + 1
missing = count * (count+1) / 2 - sum

使用bit(i,j) 获取数字很棘手,因此您必须单独提取这些位并将它们转换为实际数字以进行求和。

【讨论】:

这会读取 A 的所有 n log n 位,因此需要 n log n 时间。 @Reid:不,这根本不是 n log n。您不能同时将 n 用于位数 整数数。整数中的位数是常量,因此它实际上是O(32n)(对于32 位数字),与O(n) 完全相同。 我很确定当 OP 写“整数”时,它们的意思是“整数”,而不是“小于 2^32 的整数”。否则,只有有限多个可能的输入,所以谈论渐近运行时根本没有意义。显然,实际数学整数的长度(以位为单位)不是恒定的。 我很确定整数意味着一个固定宽度的整数,即 32 位或 1024 位,而不是基于整数值的可变长度整数。那是因为这是一个编程问答网站,固定宽度架构的数量远远超过可变宽度架构的数量:-) 无论固定宽度是 32 还是任何其他常数,都无所谓,它仍然是一个常数。我可能是错的,但基于证据的优势,我对此表示怀疑。如果您想澄清,请随时质疑 OP。如果事实证明我错了,我会删除或编辑以修复。【参考方案2】:

您可以使用 XOR 运算符,因为它比加法更快。由于您可以访问每个位,因此您将在此处进行按位异或。 这里要使用的原理是 (A XOR B XOR A ) = B

例如:(1 XOR 2 XOR 3) XOR (1 XOR 2) = 3

for i=0 to n

Total=Total XOR i


foreach element in A

Total=Total XOR element

【讨论】:

实际上,这很漂亮,+1。您不能确定 XOR 会比加法更快,但它是对使用 XOR 的二合一/一合一(例如,91 91 82 82 73 64 64 55 55)变体的巧妙修改找到单身人士。 Xor 永远不会比加法慢...为什么:此外还有一个结转位,需要一个全加器加一个步骤...在现代架构中使用并行加法器消除了它几乎相同的性能(xor 在此操作中使用少 1 个门) 1 到 n 的 XOR 有一个 O(1) 公式。 ***.com/questions/3932346/…。 XOR 还可以避免溢出问题。【参考方案3】:

那么这是一个技巧问题,因为使用 bit 方法只需要为每个数字循环每个位,这意味着它将自动变为 O(n*j),其中 j 是表示 n 的位数。

我认为 paxdiablo 已经知道了,假设您被允许使用不使用 bit 方法的解决方案。

【讨论】:

Neil,从技术上讲,这仍然是 O(n),因为 j 是一个常数。 j 在实践中是恒定的,因为整数或 long 的长度始终相同,但是 j 的有效数字以 n*2 递增 1,其中 n > 0。更像 O(log n )。

以上是关于棘手的算法问题[重复]的主要内容,如果未能解决你的问题,请参考以下文章

关于搜索的棘手面试问题

C中的棘手指针算法:** k

计算机算法设计与分析之棋盘覆盖问题

布隆过滤器实战!垃圾邮件识别?重复元素判断?缓存穿透?

为 C 示例中的棘手问题推荐一本书,如果条件异常 [重复]

算法-02 | 分治| 回溯