我知道此类问题之前已经发布过,但我想讨论一些新内容。所以,我发布了它。
给定一个未排序的整数数组,找到满足x ^ 2 + y ^ 2 = z ^ 2的所有三元组。
例如,如果给定的数组是-1,3,7,5,4,12,13 答案应该是 - 5,12,13和 3,4,5
我在下面的算法中提出了复杂性O(n ^ 2) -
现在它减少了在排序数组中找到所有三元组(a,b,c)的问题,使得a = b + c。
面试官坚持要求比O(n ^ 2)更好的解决方案。
我已经读过3SUM problem on Wikipedia,如果数字在范围[-u,u]中,则强调问题可以在O(n + ulogu)中解决,假设数组可以表示为位向量。但我无法清楚地了解进一步的解释。
有人可以通过一个很好的例子来帮助我理解发生了什么吗?
答案 0 :(得分:7)
首先。在最坏的情况下查找所有三元组是O(n^3)
。假设您有n=3k
个数字。它们的K是3,k是4,k是5。
3,....,3,4,....,4,5,.....5
有k^3 = n^3/27 = O(n^3)
个这样的三胞胎。只需打印它们需要O(n^3)
时间。
接下来将以这种形式解释3SUM问题:
s_1, ..., s_n
范围内的数字[-u;u]
分别为a,b,c
。 a+b=c
有多少个三元组a_-u, ..., a_0, a_1, ... a_u
?
转化。获得2 * u个数字a_i
。 s_j
的数量为s_j = i
,即O(n+u)
。这是在res = a_0 * sum(i=-u..u, i=/=0, C(a_i, 2)) + C(a_0,3)
a_0 = 0
P(x) = sum(i = -u...u, a_i*x^(i+u)
构建多项式Q(x) = P(x)*P(x)
。
使用FFT查找Q(x) = sum(i=-2u..2u, b_i*x^(i+2*u))
。
请注意b_i
,其中s_u
是s_k
的对数,s_u+s_k = i
i
(这包括两次使用相同的数字)。
对于所有人b_i = b_i - a_(i/2)
都b_i*a_i/2
。这将使用相同的号码删除两次。
1,2,3
- 将其添加到res。 示例:更简单,我假设数字的范围是[0..u],并且不会在x的幂中使用任何+ u。
假设我们有数字a_0 = 0, a_1 = 1, a_2 = 1, a_3 = 1
- res = 0
P(x) = x + x^2 + x^3
Q(x) = x^2 +2x^3+3x^4+2x^5+x^6
b_2 = 0, b_3 = 2, b_4 = 2, b_5 = 2, b_6 = 0
扣除res += 0*1/2 + 2*1/2 + 2*0/2 + 2*0/2 + 6*0/2 = 1
{{1}}
答案 1 :(得分:7)
另一种可能性(能够理解采访者的思想?)将重写方程式:
x^2 + y^2 = z^2
x^2 = z^2 - y^2 = (z-y)(z+y)
如果我们知道x ^ 2的素因子化,那么我们可以简单地将所有可能的因子分解为一对数p,q(p 因此,给定因子分解x ^ 2 = p.q,我们可以计算出z和y值。通过将所有整数值放入一个集合中,我们可以通过查看那些z,y值是否在数组中来检查每个可能的答案时间O(1)(每次检查)(注意也检测到负值) Wikipedia says一个随机选择的整数有大约log(n)个除数所以这应该是n.log(n),假设你可以足够快地进行因式分解(例如,如果你知道所有的整数都在百万你可以为每个整数预先计算一个最小因子的数组。)
x^2 = p.q = (z-y)(z+y)
p+q = (z-y)+(z+y) = 2z
q-p = (z+y)-(z-y) = 2y
z = (p+q)/2
y = (q-p)/2