问题很简单,飞机上有一些给定的1D线。 我们需要找到至少有一行的空间总大小。
让我用示例图像讨论这个 -
这可能是个案。或
这可能是个案或类似的事情。
我知道这是Sweep Line Algorithm的一个基本问题。
但互联网上没有适当的文件可以正确理解。
我所拥有的最好的是 Top Coder 的博客,即here。
但目前尚不清楚如何实施它或如何进行模拟。
如果我愿意,我们可以在O(n ^ 2)中使用2个循环进行,但我无法意识到该程序将如何。
或者是否有比O(n log n)更好的算法?
任何人都可以通过共享任何Sudo代码或模拟来帮助我吗?
如果Sudo代码或示例代码不可用,那么我可以通过模拟来实现这一点。
重新 Problem calculating overlapping date ranges不是我想要的,因为首先,它是O(n ^ 2)因此,它不是我想要的。并没有像这个问题那样完全描述。
答案 0 :(得分:6)
此主题的信息不多。
所以,我正在与你共享算法和模拟,由我为你创建,它也是 O(n log n) !!!!!
让我们开始 -
0
1
2
3
4
5
6
7
8
9
10
11
在你的情况下,找到数组中从1到结尾的所有元素的总和(索引号1到m),这是你的答案。
但是使用这个算法和数组,您可以轻松地获得更复杂的问题答案,例如3 shadow = Arr 3的空间长度等等。
现在问题是关于订单的内容,对吧?
所以,排序= O(n log n) 并且扫描= O(m)[m =没有动作点,所以m
所以,总顺序是= O(n log n)+ O(m)= O(n log n)
认为您可以轻松理解它,对您和其他许多人都有很大的帮助。并且认为您将能够轻松实现它。
答案 1 :(得分:0)
创建一个数组/结构列表,其中包含起点的段结束点坐标X
和+1
属性以及结束点-1
的{{1}}属性。 O(N)
按A
键排序数组。 O(NlogN)
初始化X
为零,运行数组,将CurrCount
属性添加到A
。 O(N)
您将获得CurrCount
大于零(覆盖)的范围,以及CurrCount
为零(未覆盖)的范围
答案 2 :(得分:0)
这是你可以尝试的方法(在C#中。我没有测试过,所以请原谅错字等等;只需采取“想法”/策略)。
性能为O(N log m),其中m是您将创建的不相交“阴影”的数量。所以,最糟糕的情况(如果所有的linesegments与它们的阴影不相交)你将有O(N logN),但是当你只有很少的阴影它基本上是O(N)。
public class LineSegment
{
public int Begin;
public int End;
// assumed to INCLUDE Begin but EXCLUDE End, so that
// length = End-Begin
public LineSegment Clone()
{
LineSegment clone = new LineSegment();
clone.Begin=this.Begin;
clone.End = this.End;
return clone;
}
}
public int TotalShadow(LineSegment[] segments)
{
// Class LineSegment has int members Begin and End, and Clone method to create a (shallow) Copy.
// Can/should be adapted if we're dealing with LineSegments with double/float coordinates.
// Easy special cases: no segements at all, or precisely one.
int N = segments.Length;
if (N == 0)
return 0;
else if (N == 1)
return (segments[0].End - segments[0].Begin);
// build a list of disjoint "shadows", cast onto the x-axis by all line segments together,
// sorted by their "Begin" (leftmost coordinate).
List<LineSegment> shadows = new List<LineSegment>();
// Initialize with the first segment, for convenient iteration below.
shadows.Add(segments[0].Clone());
for (int k = 1; k < N; ++k) // start at #1: we handled #0 already.
{
// find its position (Begin) in relation to the existing shadows (binary search).
int xBegin = segments[k].Begin;
int jLow = 0;
int xLow = shadows[jLow].Begin;
int jHigh, xHigh;
if (xBegin <= xLow)
jHigh = jLow; // avoid any more binary searching below
else
{
jHigh = shadows.Count - 1;
xHigh = shadows[jHigh].Begin;
if (xBegin >= xHigh)
jLow = jHigh; // avoid any more binary searching below
}
while (jHigh - jLow > 1)
{
int jTry = (jLow + jHigh) / 2;
int xTry = shadows[jTry].Begin;
if (xTry <= xBegin)
jLow = jTry;
else
jHigh = jTry;
}
// If it starts BEFORE "low" we create a new one: insert at jLow;
// Elseif x falls INSIDE "low", we merge it with low;
// ELSE we create a new shadow "between" low and high (as regards Begin)
// In all cases we'll make sure jLow points to the applicable shadow (new or existing).
// Next we'll check whether it overlaps with adjacent higher-lying shadows; if so: merge.
if (xBegin < shadows[jLow].Begin)
shadows.Insert(jLow, segments[k].Clone()); // jLow now points to the inserted item
else if (xBegin <= shadows[jLow].End)
{ // merge: extend existing low if applicable.
if (segments[k].End > shadows[jLow].End)
shadows[jLow].End = segments[k].End;
}
else // if (xBegin > shadows[jLow].End)
shadows.Insert(++jLow, segments[k].Clone()); // jLow increased to point to the inserted item.
// Try to merge, starting at the next higher lying shadow.
jHigh = jLow + 1;
while (jHigh < N && shadows[jLow].End >= shadows[jHigh].Begin)
jHigh++; // jHigh will point to the first one that we do NOT merge with.
if (jHigh > jLow + 1) // any merges?
{
if (shadows[jHigh - 1].End > shadows[jLow].End)
shadows[jLow].End = shadows[jHigh - 1].End; // set the appropriate End.
for (int jRemove = jHigh - 1; jRemove > jLow; --jRemove)
shadows.RemoveAt(jRemove); // Remove all shadaow-entries that we've merged with.
}
}
// Wrap up.
int shadowTotal = 0;
foreach (LineSegment shadow in shadows)
shadowTotal += (shadow.End - shadow.Begin);
return shadowTotal;
}
答案 3 :(得分:0)
这不是很复杂。
形成一个数组,其中您将所有区间端点abscissas都带有一个标志,告知它是起点还是终点。
越来越多地排序数组。
然后在更新计数器时扫描数组:起点增加它,结束点减少它。
从计数器从零切换到非零的值可以很容易地找到所需的大小。反之。
我不认为有可能使它比O(N Log(N))快,因为排序(我认为不能避免),除非数据允许线性时间排序(如直方图排序)。
答案 4 :(得分:0)
使用从MergeSort派生的以下方案,使用盲目排序可能会稍微好一些:
假设您有两个非重叠区间列表,按增加的界限排序;
执行合并步骤,如MergeSort(始终移动到每个列表中最近的边界),以计算间隔的并集;
根据两个列表中索引的奇偶校验,可以判断要发出哪些边界(f.i.合并AB和CDEF与排序ACBDEF,输出将是ADEF)。
这是线性时间操作。
配备此修改后的合并,您可以实现修改后的MergeSort,它以单个间隔开始并递归地形成联合。最后,您将获得一个间隔列表,它将为您提供所需的大小。
在最坏的情况下,没有约束会消失,过程仍为O(N Log(N))
。但是当出现足够多的区间联合时,间隔的数量会减少,处理时间也会缩短到线性O(N)
。