思路
缺少一个数字时,可以利用1-N
的和减去数组中元素之和得到缺少的那个数字。
在这个基础上进行扩展,缺少两个数字时,假设缺少的数字为
a
,
b
a,b
a,b且
0
<
a
<
b
0<a<b
0<a<b,如果能找到一个关于
a
,
b
a,b
a,b的二元方程组,就可以通过方程组求解的方法来得到它们的值。
可以额外利用1-N
平方和的方法得到一个
a
2
,
b
2
a^2,b^2
a2,b2的公式,由数学知识我们可知:
1
+
2
+
.
.
.
+
N
=
(
1
+
N
)
N
2
1
2
+
2
2
+
.
.
.
+
N
2
=
N
(
N
+
1
)
(
2
N
+
1
)
6
1+2+...+N = \frac{(1+N)N}{2} \\ 1^2+2^2+...+N^2 = \frac{N(N+1)(2N+1)}{6}
1+2+...+N=2(1+N)N12+22+...+N2=6N(N+1)(2N+1)
可以得到两个方程:
a
+
b
=
x
a
2
+
b
2
=
y
a+b = x \\ a^2 + b^2 = y
a+b=xa2+b2=y
通过这两个方程可以得到:
2
a
b
=
x
2
−
y
(
a
−
b
)
2
=
2
y
−
x
2
2ab = x^2 - y \\ (a-b)^2 = 2y - x^2
2ab=x2−y(a−b)2=2y−x2
由假设有:
0
<
a
<
b
0<a<b
0<a<b,所以:
a
−
b
=
−
2
y
−
x
2
a-b = -\sqrt{2y-x^2}
a−b=−2y−x2
解出
a
,
b
a,b
a,b:
a
=
x
−
2
y
−
x
2
2
b
=
x
+
2
y
−
x
2
2
a = \frac{x-\sqrt{2y-x^2}}{2} \\ b = \frac{x+\sqrt{2y-x^2}}{2}
a=2x−2y−x2b=2x+2y−x2
还需要注意的一点是,因为平方和公式的次数为三次方,且
N <= 30000
, N 3 ≤ 2.7 × 1 0 13 N^3 \le 2.7 \times 10^{13} N3≤2.7×1013,会爆int,需要使用long类型来存储
代码如下:
class Solution {
public int[] missingTwo(int[] nums) {
int n = nums.length + 2;
//设缺少的两个数为a,b
// a+b = x
long x = n*(1+n)/2 - Arrays.stream(nums).mapToLong(a->a).sum();
// a^2 + b^2 = y
long y = n*(1+n)*(1 + 2L *n)/6 - Arrays.stream(nums).mapToLong(a -> (long) a * a).sum();
// 2ab = x^2 - y
// (a-b) ^ 2 = 2y-x^2
// 假设 a < b 则有 a-b = -√(2y-x^2)
// a = [x-√(2y-x^2)]/2
// b = [x+√(2y-x^2)]/2
long sqrt = (long) Math.sqrt(2 * y - x * x);
return new int[]{(int) ((x - sqrt)/2), (int) ((x + sqrt)/2)};
}
}