NumberOfDiscIntersections 题目链接
O(N*log(N)) \textrm{O(N*log(N))} O(N*log(N)) Solution
O(N*log(N)) \textrm{O(N*log(N))} O(N*log(N)) 的做法,将二维的圆压缩成一维的线段(因为圆的圆心在同一条 x \textrm{x} x 轴上),将线段按照左端点排序后遍历累加。
O(N) \textrm{O(N)} O(N) Solution
这个做法妙得让我拍案叫绝
参考:https://stackoverflow.com/a/16814894/15480731
-
将每个圆的左端点和右端点处理出来
-
每次遍历到一个点,得到将该点作为左端点的线段(圆)的数量,称他们为新的 a c t i v e D i s c activeDisc activeDisc
-
这些新的 a c t i v e D i s c activeDisc activeDisc 与旧的 a c t i v e D i s c activeDisc activeDisc 必然相交,同时这些新的 a c t i v e D i s c activeDisc activeDisc 也必然两两相交,即有 res+= ( l e f t ( i ) ∗ a c t i v e D i s c + C a c t i v e D i s c 2 ) \textrm{res+=}(left(i)*activeDisc+C_{activeDisc}^{2}) res+=(left(i)∗activeDisc+CactiveDisc2)
-
把 将该点作为右端点的线段(圆) 从 a c t i v e D i s c activeDisc activeDisc 中减去。
int solution(int A[], int N)
{
static int left[100005], right[100005];
int result = 0;
for (int i = 0; i < N; i++) //处理出每个圆的左边界和右边界
{
if (i - A[i] <= 0) //判断左边界是否超过0
left[0]++;
else
left[i - A[i]]++;
if (A[i] >= N || i + A[i] >= N) //要小心A[i]+i会溢出int的范围
right[N - 1]++;
else
right[i + A[i]]++;
}
int activeDisc = 0;
for (int i = 0; i < N; i++)
{
if (left[i] > 0)
{
result += activeDisc * left[i]; //在这一点新加入的圆与之前存在的所有圆相交
result += left[i] * (left[i] - 1) / 2; //在这一点新加入的圆之间两两相交
if (result > 1e7)
return -1;
activeDisc += left[i];
}
activeDisc -= right[i]; //减去已到达右边界的圆
}
return result;
}