计算交叉盘数的算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算交叉盘数的算法相关的知识,希望对你有一定的参考价值。
给定A
整数的N
数组,我们在2D平面上绘制N
圆盘,这样第i个圆盘的中心位于(0,i)
,半径为A[i]
。如果第k个和第j个盘具有至少一个公共点,我们说第k个盘和第j个盘相交。
写一个函数
int number_of_disc_intersections(int[] A);
如上所述给出了描述A
光盘的数组N
,返回相交光盘对的数量。例如,给定N=6
和
A[0] = 1
A[1] = 5
A[2] = 2
A[3] = 1
A[4] = 4
A[5] = 0
共有11对交叉盘:
0th and 1st
0th and 2nd
0th and 4th
1st and 2nd
1st and 3rd
1st and 4th
1st and 5th
2nd and 3rd
2nd and 4th
3rd and 4th
4th and 5th
所以函数应该返回11.如果相交对的数量超过10,000,000,函数应该返回-1。该函数可以假设N
不超过10,000,000。
所以你想找到间隔[i-A[i], i+A[i]]
的交叉点数。
维护一个包含i-A[i]
的排序数组(称之为X)(还有一些额外的空间,其中有i+A[i]
值)。
现在走到阵列X,从最左边的间隔开始(即最小的i-A[i]
)。
对于当前间隔,进行二分搜索以查看间隔的右端点(即i+A[i]
)将去向何处(称为等级)。现在您知道它与左侧的所有元素相交。
增加一个具有等级的计数器并减去当前位置(假设一个被索引),因为我们不想重复计算间隔和自交叉。
O(nlogn)时间,O(n)空间。
count = 0
for (int i = 0; i < N; i++) {
for (int j = i+1; j < N; j++) {
if (i + A[i] >= j - A[j]) count++;
}
}
它是O(N^2)
非常慢,但它的工作原理。
这是一种红宝石解决方案,在编码方面得分为100/100。我现在发布它,因为我发现很难按照已经发布的ruby回答。
def solution(a)
end_points = []
a.each_with_index do |ai, i|
end_points << [i - ai, i + ai]
end
end_points = end_points.sort_by { |points| points[0]}
intersecting_pairs = 0
end_points.each_with_index do |point, index|
lep, hep = point
pairs = bsearch(end_points, index, end_points.size - 1, hep)
return -1 if 10000000 - pairs + index < intersecting_pairs
intersecting_pairs += (pairs - index)
end
return intersecting_pairs
end
# This method returns the maximally appropriate position
# where the higher end-point may have been inserted.
def bsearch(a, l, u, x)
if l == u
if x >= a[u][0]
return u
else
return l - 1
end
end
mid = (l + u)/2
# Notice that we are searching in higher range
# even if we have found equality.
if a[mid][0] <= x
return bsearch(a, mid+1, u, x)
else
return bsearch(a, l, mid, x)
end
end
100/100 c#
class Solution
{
class Interval
{
public long Left;
public long Right;
}
public int solution(int[] A)
{
if (A == null || A.Length < 1)
{
return 0;
}
var itervals = new Interval[A.Length];
for (int i = 0; i < A.Length; i++)
{
// use long to avoid data overflow (eg. int.MaxValue + 1)
long radius = A[i];
itervals[i] = new Interval()
{
Left = i - radius,
Right = i + radius
};
}
itervals = itervals.OrderBy(i => i.Left).ToArray();
int result = 0;
for (int i = 0; i < itervals.Length; i++)
{
var right = itervals[i].Right;
for (int j = i + 1; j < itervals.Length && itervals[j].Left <= right; j++)
{
result++;
if (result > 10000000)
{
return -1;
}
}
}
return result;
}
}
可能非常快。上)。但你需要检查一下。 100%的Codility。主要思想:1。在桌子的任何一点,有多个圆圈“打开”直到圆圈的右边缘,让我们说“o”。因此,该点的圆圈有(o-1次使用的)可能的对。 “used”表示已经处理的圆圈,并且对它们进行计数。
public int solution(int[] A) {
final int N = A.length;
final int M = N + 2;
int[] left = new int[M]; // values of nb of "left" edges of the circles in that point
int[] sleft = new int[M]; // prefix sum of left[]
int il, ir; // index of the "left" and of the "right" edge of the circle
for (int i = 0; i < N; i++) { // counting left edges
il = tl(i, A);
left[il]++;
}
sleft[0] = left[0];
for (int i = 1; i < M; i++) {// counting prefix sums for future use
sleft[i]=sleft[i-1]+left[i];
}
int o, pairs, total_p = 0, total_used=0;
for (int i = 0; i < N; i++) { // counting pairs
ir = tr(i, A, M);
o = sleft[ir]; // nb of open till right edge
pairs = o -1 - total_used;
total_used++;
total_p += pairs;
}
if(total_p > 10000000){
total_p = -1;
}
return total_p;
}
private int tl(int i, int[] A){
int tl = i - A[i]; // index of "begin" of the circle
if (tl < 0) {
tl = 0;
} else {
tl = i - A[i] + 1;
}
return tl;
}
int tr(int i, int[] A, int M){
int tr; // index of "end" of the circle
if (Integer.MAX_VALUE - i < A[i] || i + A[i] >= M - 1) {
tr = M - 1;
} else {
tr = i + A[i] + 1;
}
return tr;
}
这在c#中得到100/100
class CodilityDemo3
{
public static int GetIntersections(int[] A)
{
if (A == null)
{
return 0;
}
int size = A.Length;
if (size <= 1)
{
return 0;
}
List<Line> lines = new List<Line>();
for (int i = 0; i < size; i++)
{
if (A[i] >= 0)
{
lines.Add(new Line(i - A[i], i + A[i]));
}
}
lines.Sort(Line.CompareLines);
size = lines.Count;
int intersects = 0;
for (int i = 0; i < size; i++)
{
Line ln1 = lines[i];
for (int j = i + 1; j < size; j++)
{
Line ln2 = lines[j];
if (ln2.YStart <= ln1.YEnd)
{
intersects += 1;
if (intersects > 10000000)
{
return -1;
}
}
else
{
break;
}
}
}
return intersects;
}
}
public class Line
{
public Line(double ystart, double yend)
{
YStart = ystart;
YEnd = yend;
}
public double YStart { get; set; }
public double YEnd { get; set; }
public static int CompareLines(Line line1, Line line2)
{
return (line1.YStart.CompareTo(line2.YStart));
}
}
}
感谢Falk的好主意!这是一个利用稀疏性的ruby实现。
def int(a)
event = Hash.new{|h,k| h[k] = {:start => 0, :stop => 0}}
a.each_index {|i|
event[i - a[i]][:start] += 1
event[i + a[i]][:stop ] += 1
}
sorted_events = (event.sort_by {|index, value| index}).map! {|n| n[1]}
past_start = 0
intersect = 0
sorted_events.each {|e|
intersect += e[:start] * (e[:start]-1) / 2 +
e[:start] * past_start
past_start += e[:start]
past_start -= e[:stop]
}
return intersect
end
puts int [1,1]
puts int [1,5,2,1,4,0]
#include <stdio.h>
#include <stdlib.h>
void sortPairs(int bounds[], int len){
int i,j, temp;
for(i=0;i<(len-1);i++){
for(j=i+1;j<len;j++){
if(bounds[i] > bounds[j]){
temp = bounds[i];
bounds[i] = bounds[j];
bounds[j] = temp;
temp = bounds[i+len];
bounds[i+len] = bounds[j+len];
bounds[j+len] = temp;
}
}
}
}
int adjacentPointPairsCount(int a[], int len){
int count=0,i,j;
int *bounds;
if(len<2) {
goto toend;
}
bounds = malloc(sizeof(int)*len *2);
for(i=0; i< len; i++){
bounds[i] = i-a[i];
bounds[i+len] = i+a[i];
}
sortPairs(bounds, len);
for(i=0;i<len;i++){
int currentBound = bounds[i+len];
for(j=i+1;a[j]<=currentBound;j++){
if(count>100000){
count=-1;
goto toend;
}
count++;
}
}以上是关于计算交叉盘数的算法的主要内容,如果未能解决你的问题,请参考以下文章