包含在奇数集中的数字

时间:2012-05-09 18:01:48

标签: c++ algorithm

我有一个家庭作业问题,我只能在O(max(F)*N)N约为10^5F10^9)复杂性时解决这个问题,我希望你可以帮帮我我获得了N套4个integer个数字(名为S, F, ab);每组4个数字以这种方式描述一组数字:第一个连续数字,从S开始包含在集合中。接下来的b个连续数字不是,然后是下一个a数字,重复此数字直到达到上限F。例如,对于S=5;F=50;a=1;b=19,该集合包含(5,25,45); S=1;F=10;a=2;b=1,该集合包含(1,2,4,5,7,8,10);

我需要找到包含在奇数个集合中的整数。保证对于给定的测试,只有1个数字符合这一条件。

我试图通过min(S)max(F)之间的每个数字来检查这个数字包含多少套数,如果它包含在奇数个数组中,那么这是答案。正如我所说,通过这种方式,我得到一个O (F*N)太多了,我不知道怎么能看到一个数字是否在奇数集中。

如果你能帮助我,我会非常感激。提前谢谢你,对不起我的英语和解释感到抱歉!

4 个答案:

答案 0 :(得分:3)

提示

我很想使用二分法。

选择一个值x,然后计算所有集合中存在的数字< = x。

如果这是奇数,那么答案是< = x,否则> x。

这应该花费时间O(Nlog(F))

替代解释

假设我们有设置

[S=1,F=8,a=2,b=1]->(1,2,4,5,7,8) 
[S=1,F=7,a=1,b=0]->(1,2,3,4,5,6,7) 
[S=6,F=8,a=1,b=1]->(6,8)

然后我们可以表:

N(y)= y包含在集合中的次数,

C(z)= sum(范围(1,z)中y的N(y))%2

y  N(y)  C(z)
1  2     0
2  2     0
3  1     1
4  2     1
5  2     1
6  2     1
7  2     1
8  2     1

然后我们使用二分法找到C(z)变为1的第一个位置。

答案 1 :(得分:1)

似乎有必要在这些集合上找到一种方法来执行集合操作,特别是交集,而无需生成实际集合。如果你能做到这一点,测试中所有这些集合的交集应该只留下一个数字。将ab部分放在一边,很容易看出你如何取两个包含S和F之间所有整数的集合的交集:交集只是S = max的集合( S1,S2)和F = min(F1,F2)。

这给你一个起点;现在你必须弄清楚如何创建考虑ab的两组交集。

答案 2 :(得分:1)

XOR救援。

从每个连续集中获取数字,并使用结果集的内容对它们进行异或。即,如果该号码当前标记为“存在”,则将其更改为“不存在”,反之亦然。

最后,您将在结果集中标记一个数字,这个数字将出现奇数次。所有其他人都会进行多次异或,所以他们将恢复原状。

至于复杂性,你只需要处理每个输入项一次,所以它基本上是输入项总数的线性 - 至少假设你对结果集的操作是恒定的复杂性。至少如果我理解他们是如何措辞的话,那似乎符合要求。

答案 3 :(得分:0)

听起来S被认为是非负面的。鉴于您对O(max(F)*N)时间边界的渴望,您可以使用类似筛分的方法。

有一个整数数组,每个候选数字都有一个条目(即min(S)和max(F)之间的每个数字)。遍历所有四元组,并将1添加到与每个四元组所代表的数字相关的所有数组位置。最后,查看数组以查看哪个计数是奇数。它代表的数字是满足您条件的数字。

这是有效的,因为你将进入N个四倍,并且每个都需要O(最大(F))或更少的时间(假设S总是非负的)来计算包含的数字。这给你O(最大(F)* N)。