设计一个采用 O(n log n) 确定的分治算法
Posted
技术标签:
【中文标题】设计一个采用 O(n log n) 确定的分治算法【英文标题】:design a divide and conquer algorithm that takes O(n log n) determinations 【发布时间】:2015-12-03 11:58:09 【问题描述】:我得到一组球,我的最终目标是找出至少一半的球是相同颜色的。我每次只能挑两个球,判断它们是否相同颜色。那么如何设计一个分治算法来解决这个问题呢?如果有人对此问题有任何想法,非常感谢!
【问题讨论】:
我认为这个问题需要编辑以包含对“查询”一词的更好解释。具体来说,查询的功能和限制是什么? 感谢您的提示,我做了一点改动,希望现在容易理解。 @JasonLee 你有固定数量的颜色吗?可以以某种方式订购它们吗?或者只比较平等。 很遗憾,它们只能进行相等比较... 【参考方案1】:也许你可以倒着做——如果你不知道n(log n)
比较中的答案,那么只有不到一半的球是相同颜色的。对它们进行合并排序分组...
r g r b r y r r // worst case arrangement
rg rb ry rr
↓ // 3 * (n / 4) comparisons
rr gb rrr y
↓ // 3 * (n / 8) comparisons
rrrrr gby
【讨论】:
好像是我想要的,非常感谢!【参考方案2】:我们可以将您的问题简化为以下问题。
如果给定集合中的球按颜色分组,您希望找出最大的组是否至少是集合大小的一半。
这更容易递归解决。 (这个问题不针对空集定义,单独处理。)
class Group // with appropriate constructors
int size;
Color color;
Group findLargestGroupWithSameColors(Set<Ball> ballSet)
if (ballSet.size() > 1)
// Divide set into two (preferably equal) sets.
Group first = recursive call on first half.
Group second = recursive call on second half.
if (first.color.equals(second.color))
return new Group(first.color, first.size + second.size);
else
if (first.size > second.size)
return first;
else
return second;
else
return single element's color and size = 1
祝你好运
【讨论】:
如果你只返回最大的组,我担心,在某些配置中,你会错过可能通过随后合并较小集而形成的最大组。 例如A B A B A C A C. 在 2 个元素集 (AB)(AB)(AC)(AC) 上,您的算法总是返回第二个元素 (2xB)(2xC),完全忽略 As。 与我想要的有点不同...谢谢!【参考方案3】:我假设您可以对颜色进行排序(例如,您可以将颜色的散列计算为可以排序的整数;我想不出任何不能散列的数据类型)。然后你可以简单地在O(n log n)
时间按颜色对球进行排序,然后在排序后的集合中扫描一次,确定连续相同颜色的球的运行。你的答案是,最大跑的球数是否 >= 球数。
编辑
问题实际上是 O(n)。对 n 个球使用具有 O(1) 插入的哈希表。每当你已经拥有它时,增加哈希表组中元素的计数,并在其他地方跟踪最大的组计数。
您甚至可以在最大计数达到 n/2 时提前退出,这应该是随机集平均运行时间的一半。
编辑2
O(n^2) 的示例证明示意图
我坚信,当只允许相等比较时,没有 O(n log n) 解决方案。看下面的例子,应该是 true,正好有一半是 As,其余的都不一样:
第一次划分
n = 16
AAAAAAABCDEFGHIA
AAAAAAAB CDEFGHIA
AAAA AAAB CDEF GHIA
AA AA AA AB CD EF GH IA
现在征服。我们需要在每个征服步骤中找到所有组,因为每个组都可能与另一个大组合并,因此它是所有组的大多数。
在这个例子中,int 左半边 A 显然是赢家,但我们需要在右半边再增加一个 A。由于在分而治之的情况下,右半部分不知道左半部分,因此在最终合并之前,右侧也会尝试找到最大的组,以 n/2 个大小为 1 的组结束。
在下面的符号中,我在字母前使用一个数字来表示找到的那个大小的组。
2A 2A 2A 1A1B 1C1D 1E1F 1G1H 1I1A 1+1+1+1 +1+1+1+1 =4+4 =8
4A 3A1B 1C1D1E1F 1G1H1I1A 1*1+2*1 +2*2+2*2 =3+8 =11
7A1B 1C1D1E1F1G1H1I1A 1*2 +4*4 =2+16=18
8A1B1C1D1E1F1G1H1I 2*8 =16
53
n log2 n = 16*4=64
在右侧,我注意到合并组所需的比较次数。要将包含 x 组的集合和包含 y 组的集合合并,您需要 O(x y) 比较,当这两个集合不相交时需要(即,将一组中的每一组与另一组中的每一组进行比较)。 本例需要 53 次比较,低于 64 的 n log2 n。 左侧的比较表现得非常线性。如果你分析你得到的模式(对于 n>7)
Log2(n)-2+ Sumi=0..Log2(n)(2^i) = n/2 - 3 + Log2(n)
但是等等,在正确的比较次数上有一个平方项。让我们检查一下。每行(最后一次合并除外)都将前一行翻倍,并以 (n/4)^2 比较结束。这给了
Sumi=0..Log2(n)-2( (n/4)^2 (1/2)^i ) = 1/8 (n^2 - 2*n)
因此,确实,通过这种分而治之的方法,我们最坏情况下的比较次数是 O(n^2),这似乎是合乎逻辑的。如果所有条目都不同,并且每次只能测试两个是否相等,则需要对每个条目进行测试以查找是否真的没有对。
不知道我是否遗漏了什么,但是当只允许comarisons时,这个问题似乎在O(n log n)中无法通过分而治之来解决。
【讨论】:
其实是算法题,所以有限制。我认为你在现实世界的项目中给出了正确的解决方案,还是谢谢你!以上是关于设计一个采用 O(n log n) 确定的分治算法的主要内容,如果未能解决你的问题,请参考以下文章