Java 使用树集计算磁盘交点
在我把真正的考试作为求职申请的一部分之前,我正在尝试一个关于可变性的演示问题。他们演示的一个问题是计算磁盘阵列的磁盘交叉数 任务描述为 给定一个由N个整数组成的数组,我们在一个二维平面上画N个圆盘,如 第I个圆盘以(0,I)为中心,半径为[I]。我们 假设第J个圆盘和第K个圆盘相交,如果J≠ K和J-th和 第K个光盘至少有一个公共点。编写一个函数:class 解{public int number_of_disc_crossions(int[]A)}表示, 如上所述,给定一个描述N个光盘的数组,返回 交叉盘的对数 您可以查看测试 有一些明显的O(n^2)时间复杂度解决方案,但目标是O(n*log(n)) 我提出了这个,它适用于我提供的任何示例,以及Codibility([1,5,2,1,4,0])给出的简单测试用例,但Codibility告诉我它在大多数其他示例中都失败了,但我不太明白为什么 它当然应该是O(n log n),因为将n个磁盘中的每一个添加到树集就是log n,然后我们将遍历每个磁盘,只使用O(1)操作TreeSet.header()Java 使用树集计算磁盘交点,java,Java,在我把真正的考试作为求职申请的一部分之前,我正在尝试一个关于可变性的演示问题。他们演示的一个问题是计算磁盘阵列的磁盘交叉数 任务描述为 给定一个由N个整数组成的数组,我们在一个二维平面上画N个圆盘,如 第I个圆盘以(0,I)为中心,半径为[I]。我们 假设第J个圆盘和第K个圆盘相交,如果J≠ K和J-th和 第K个光盘至少有一个公共点。编写一个函数:class 解{public int number_of_disc_crossions(int[]A)}表示, 如上所述,给定一个描述N个光盘的数组
import java.util.*;
类循环实现了可比性{
长边;
整数指数;
圆(长e,内i){
边缘=e;
指数=i;
}
long getRightAssumingEdgeIsLeft(){
返回(长)(2*索引-边缘+1);
}
@凌驾
公共整数比较(圈出其他){
返回Long.valueOf(edge).compareTo(其他.edge);
}
}
类解决方案{
交叉口的公共整数编号(整数[]A){
int N=A.长度;
if(N第一件事:您定义了compareTo()而不是equals()。TreeSet JavaDoc说:“集合维护的顺序(无论是否提供显式比较器)必须与equals一致”
其他奇怪之处:我不明白什么是edge
字段,也不明白为什么要将它设置为I-A[I]
一个不同的算法(O(N log N)
):
这是一幅糟糕的场景图:
可以转换为范围列表:(不完全相同的场景)
图2
O(N logn):我们首先对标记进行排序,如果我们想将相切圆盘计算为重叠,则要注意绿色标记出现在红色标记之前
O(N):我们从左到右扫描,初始值为total
=0
,初始值为=0
。每次点击绿色标记时,total+=1
,在每个红色标记处,total-=1
。此外,在每个绿色标记处,如果total>0,则重叠+=total
图2中的黑色数字是每一步的总数;橙色是重叠的
然后,重叠
应该是答案
请参见此处的粗略实现:有一种更简单的方法
这样,我们实际上只在每个排序数组中循环一次,因此算法的复杂度为O(N logn)。假设j总是大于i,为了满足两个圆的相互作用,下面的不等式应该始终有效:
|R(i) - R(j)| <= j - i <= R(i) + R(j)
| R(i)-R(j)|我做了同样的演示,为一个编程职位做准备。我没有及时开发解决方案,结果得到了一个糟糕的分数(十几岁的时候)。然而,我对这个问题很感兴趣,我继续自己完成了它。以下是我的解决方案:
============================================================================
Name : cFundementalsTest.c
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main(void) {
int N = 5;
int A[6] = {1, 5, 2, 1, 4, 0 };
int pos_1, pos_2;
int total;
for(pos_1=0;pos_1<=N;pos_1++)
{
for(pos_2=pos_1+1;pos_2<=N;pos_2++)
{
if(A[pos_1] + A[pos_2] >= abs(pos_1 - pos_2))
{ // they share a common point
total++;
printf("%d and %d\n",pos_1, pos_2);
if(total > 10000000)
return(-1);
}
}
}
printf ("\n\n the total is %d",total);
}
此方法不需要任何特殊类(如圆形)或复杂容器(如PriorityQueue或TreeSet)。只需要简单的整数数组。它是O(N*logN)。语言为Java
public int numberOfDiscIntersections(int [] A) {
// 0 <= A.length <= 100,000
// 0 <= A[i] <= 2147483647
int [] leftEdge = new int[A.length];
int [] rightEdge = new int[A.length];
int maxLength = 100000;
// maxLength is used to prevent integers > 2147483647
// and integers < -2147483647
for (int i = 0; i < A.length; i++) {
leftEdge[i] = i - A[i];
rightEdge[i] = i - maxLength + A[i];
}
Arrays.sort(leftEdge);
Arrays.sort(rightEdge);
int sum = mergeAndCountOverlaps(leftEdge,rightEdge, maxLength);
return sum;
}
Disc交叉口的公共int编号(int[]A){
//0上,您需要使用排序来解决它,对吗?下面是JavaScript解决方案通过100%测试
我们在轴x
上使用两个范围数组。两个数组中的值相同,但首先按从
参数排序,其次按到
(两者均为升序)。然后我们同时扫描两个数组并跟踪重叠以计数不同的对
您可以在中使用此代码
功能解决方案(arr){
常量r1=arr.map((n,i)=>({from:i-n,to:n+i})).sort((a,b)=>a.from-b.from)
常量r2=r1.slice().sort((a,b)=>a.to-b.to)
设i=0,j=0
设重叠=0
设对=0
而(i
类解决方案{
公共int解决方案(int[]A){
//用JavaSE8编写代码
long[]leftpoint=新的long[A.length];
long[]rigthpoint=新长[A.长度];
如果(A.length)边缘有点不清楚。该字段通常表示光盘的左边缘-它是i-A[i],因为i是中心,A[i]是半径。我也会尝试实现equals,但我没有想到。我认为TreeSet只使用compareTo,而实现equals是使代码经得起未来考验的良好实践。如果磁盘的坐标是(0,I)(传统上是(x,y)坐标),那么它们是垂直对齐的,所以我不明白为什么要计算左边缘。即使这只是一个词汇,我也不明白按边缘位置对圆排序如何解决相交问题(应该在半径之和小于圆之间的距离时解决)。这是真的,我说
#include <stdlib.h>
public int number_of_disc_intersections(int[] A){
int len = A.length;
int intersections = 0;
for(int i = 0; i < len - 1; i++){
if(A[i] <= 0){
continue;
}
for(int j = i + 1; j < len; j++){
if(A[j] <= 0){
continue;
}
if(abs((A[i] - A[j]) <= j - i) && (j - i <= A[i] + A[j])){
intersections ++;
}
}
}
return intersections;
}
============================================================================
Name : cFundementalsTest.c
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main(void) {
int N = 5;
int A[6] = {1, 5, 2, 1, 4, 0 };
int pos_1, pos_2;
int total;
for(pos_1=0;pos_1<=N;pos_1++)
{
for(pos_2=pos_1+1;pos_2<=N;pos_2++)
{
if(A[pos_1] + A[pos_2] >= abs(pos_1 - pos_2))
{ // they share a common point
total++;
printf("%d and %d\n",pos_1, pos_2);
if(total > 10000000)
return(-1);
}
}
}
printf ("\n\n the total is %d",total);
}
0 and 1
0 and 2
0 and 4
1 and 2
1 and 3
1 and 4
1 and 5
2 and 3
2 and 4
3 and 4
4 and 5
the total is 11
public int numberOfDiscIntersections(int [] A) {
// 0 <= A.length <= 100,000
// 0 <= A[i] <= 2147483647
int [] leftEdge = new int[A.length];
int [] rightEdge = new int[A.length];
int maxLength = 100000;
// maxLength is used to prevent integers > 2147483647
// and integers < -2147483647
for (int i = 0; i < A.length; i++) {
leftEdge[i] = i - A[i];
rightEdge[i] = i - maxLength + A[i];
}
Arrays.sort(leftEdge);
Arrays.sort(rightEdge);
int sum = mergeAndCountOverlaps(leftEdge,rightEdge, maxLength);
return sum;
}
private int mergeAndCountOverlaps(int[] leftEdge, int [] rightEdge, int maxLength) {
int leftIndex = 0;
int rightIndex = 0;
int sum = 0;
int total = 0;
while ((leftIndex < leftEdge.length) || (rightIndex < rightEdge.length)) {
if ((leftIndex < leftEdge.length) && (rightIndex < rightEdge.length)) {
boolean compareLeftEdgeandRightEdge;
if (leftEdge[leftIndex] < -2147483647 + maxLength) {
compareLeftEdgeandRightEdge = leftEdge[leftIndex] <= rightEdge[rightIndex] + maxLength;
} else {
compareLeftEdgeandRightEdge = leftEdge[leftIndex] - maxLength <= rightEdge[rightIndex];
}
if (compareLeftEdgeandRightEdge) {
// a new left edge
sum += total;
if (sum > 10000000) {
return -1;
}
total++;
leftIndex++;
} else {
// a new right edge
total--;
rightIndex++;
}
} else if (leftIndex < leftEdge.length) {
// a new left edge
sum += total;
if (sum > 10000000) {
return -1;
}
total++;
leftIndex++;
} else if (rightIndex < rightEdge.length) {
// a new right edge
total--;
rightIndex++;
}
}
return sum;
}
function solution(arr) {
const r1 = arr.map((n, i) => ({from: i - n, to: n + i})).sort((a, b) => a.from - b.from)
const r2 = r1.slice().sort((a, b) => a.to - b.to)
let i = 0, j = 0
let overlaps = 0
let pairs = 0
while (i < r1.length || j < r2.length) {
if (i < r1.length && r1[i].from <= r2[j].to) {
pairs += overlaps
if (pairs > 10000000) {
return -1
}
overlaps++
i++
} else {
overlaps--
j++
}
}
return pairs
}
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
long[] leftpoint=new long[A.length];
long[] rigthpoint=new long[A.length];
if(A.length<2)return 0;
for(int i=0;i<A.length;++i){
leftpoint[i]=-A[i];
leftpoint[i]+=i;
rigthpoint[i]=A[i];
rigthpoint[i]+=i;
}
Arrays.sort(leftpoint);
Arrays.sort(rigthpoint);
int intersection =0;
int j=0;
int i=0;
int open=0;
while(i<A.length&&j<A.length){
if(rigthpoint[i]>=leftpoint[j]){
intersection+=open;
open++;
j++;
}else{
open--;
i++;
}
if(intersection>10000000)return -1;
}
return intersection;
}
}