【发布时间】:2018-07-25 04:06:00
【问题描述】:
我尝试从 Codility 解决问题,
我们在一个平面上画 N 个圆盘。圆盘的编号从 0 到 N - 1。给出了一个由 N 个非负整数组成的数组 A,指定圆盘的半径。第 J 个圆盘以 (J, 0) 为中心,半径为 A[J] 绘制。
如果 J ≠ K,我们说第 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
有十一对(无序)相交的圆盘,即:
圆盘 1 和 4 相交,并且都与所有其他圆盘相交; 圆盘 2 也与圆盘 0 和 3 相交。 写一个函数:
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] 范围内的整数。 复杂性:
预期的最坏情况时间复杂度为 O(N*log(N)); 预期的最坏情况空间复杂度为 O(N)(不计算输入参数所需的存储空间)。
我也有一个我试图理解的解决方案,
public static int solution(int[] A) {
int N = A.length;
int[] sum = new int[N];
for (int i = 0; i < N; i++) {
int right;
if (N - 1 >= A[i] + i) {
right = i + A[i];
} else {
right = N - 1;
}
sum[right]++;
}
for (int i = 1; i < N; i++) {
sum[i] += sum[i - 1];
}
int result = N * (N - 1) / 2;
for (int j = 0; j < N; j++) {
int left;
if (j - A[j] < 0) {
left = 0;
} else {
left = j - A[j];
}
if (left > 0) {
result -= sum[left - 1];//.
}
}
if (result > 10000000) {
return -1;
}
return result;
}
虽然我部分理解了解决方案,但我无法完全理解它。我在下面描述它,
我。我们创建了一个长度为N 的数组sum,并用圆盘最右边的点作为索引填充。如果最右边的点大于N-1,我们将其设置为N-1
二。执行数组sum的前缀和,即扫描数字序列x0、x1、x2、...是第二个数字序列y0、y1、y2、...,前缀之和(运行总数) 的输入序列:
x0 = x0
x1 = x0 + x1
x2 = x0 + x1+ x2
三。计算所提供数组的最大可能交集N * (N - 1) / 2
结果来自于从 2 个元素的 15 种可能组合中进行选择,即C(N,R)。如果R = 2,我们可以推导出C(N,R)=N!/R!* (N−R)!给N * (N - 1) / 2
四。找到最左边的点,如果值小于零,则将其设置为零。然后,如果左值大于零,则将其转换为结果中的索引和物质。
首先,我不明白最后一步发生了什么。谁能解释得更好?我认为在最后一行result -= sum[left - 1] 我们从最大可能中扣除了对没有交集,现在我尝试理解计算
【问题讨论】: