源地址
https://app.codility.com/programmers/lessons/6-sorting/number_of_disc_intersections/
NumberOfDiscIntersections(圓盤交集數)
我們在一個平面上畫N個圓盤,標記爲0到N-1 ,一個含有N個非負整數的數組A,表示這些圓盤的半徑,第J個圓盤,他的圓心在 (J, 0) ,並且半徑爲A[J].
我們說圓盤J和圓盤K有交集,如果J≠K,並且這兩個圓盤至少有一個共同的點(假定圓盤包括他們的邊).
比如N=6、並有如下的數組A:
A[0] = 1
A[1] = 5
A[2] = 2
A[3] = 1
A[4] = 4
A[5] = 0
有11個圓盤交集(非排序):
- 1 和4有交集,並且都和其他所有的圓盤都有
- 2 和 0 以及4 有交集
寫一個函數
class Solution {
public int solution(int[] A);
}
給定一個代表N個圓盤的數組A,返回有交集的圓盤的數量.如果交集數量大於10,000,000,返回-1.
比如上面給出的數組A,函數返回11.
假定:
- N是範圍在 [0…100,000]的整數
- A中的每個元素都是範圍在[0…2,147,483,647]的整數
第一步
有A個圓疊加時,兩兩配對的計算公式爲 (A * (A-1) )/ 2(高中集合論?)
用兩個長度爲N的數組,分別記錄到各個圓心的左邊界和右邊界,然後遍歷圓心,計算出到每個圓心座標時新增加的圓的數量.
注意半徑可能爲Integer.Max_Value,需要考慮溢出的情況.
public int solution(int[] A) {
int N = A.length;
if (N == 0)
return 0;
int[] leftArr = new int[N];
int[] rightArr = new int[N];
for (int i = 0; i < N; i++) {
int left = Math.max(0, i - A[i]);
leftArr[left]++;
int right = Math.min(N - 1, i + A[i]);
if (i > Integer.MAX_VALUE - A[i]) {
right = N - 1;
}
rightArr[right]++;
}
int level = 0;
int result = 0;
for (int i = 0; i < N; i++) {
if (leftArr[i] > 0) {
int num = level * leftArr[i] + (leftArr[i] * (leftArr[i] - 1)) / 2;
result += num;
if (result > 10000000)
return -1;
}
level = level - rightArr[i] + leftArr[i];
}
return result;
}