合并天际线,分而治之
Posted
技术标签:
【中文标题】合并天际线,分而治之【英文标题】:Merge skylines, divide and conquer 【发布时间】:2013-02-05 07:20:37 【问题描述】:我正在尝试解决著名的天际线问题(见 gif):
输入
(1,11,5), (2,6,7), (3,13,9), (12,7,16), (14,3,25), (19,18,22) , (23,13,29), (24,4,28)
应该返回,其他建筑物后面的点应该没有了,Y轴变化的坐标应该在返回的天际线中:
(1, 11), (3, 13), (9, 0), (12, 7), (16, 3), (19, 18), (22, 3), (23, 13) , (29, 0)
我试图通过对算法使用分而治之的方法来实现 O(n lg n) 的运行时间,但我被困在合并部分。
每当我想到它时,我都会感到困惑。例如,我检查天际线首先是哪一个,例如它具有较低的 x 坐标,然后我将 + 它的高度添加到我的新天际线中。但是后来我遇到了在另外两个天际线后面的天际线,我怎样才能检测到这种“碰撞”?
我是否首先通过检查 left.x2
也许我想得太复杂了?我需要的是一组最高的 y 坐标,在每个路口,我应该这样接近它吗?
【问题讨论】:
【参考方案1】:我认为这应该是一种更容易理解的方法:
将 x 坐标拆分为每个矩形的开始和结束对象,如下所示:
rect(x1, y, x2) -> (x1, y, "start", reference to rect),
(x2, y, "finish", reference to rect)
比如:
class MyStruct
Rectangle rect;
int x, y;
bool isStart;
按 x 坐标对这些对象进行排序 (O(n log n)
)
创建一组(最初为空)矩形(将按 y 坐标排序,例如 BST)
循环遍历这些对象(按现在排序的顺序)(O(n)
)
每当遇到启动时
将矩形添加到矩形集中 (O(log n)
)
如果是新的最高矩形,则将该起点添加到输出 (O(1)
)
每当遇到完成时
从矩形集中移除矩形 (O(log n)
)
如果是最高矩形,则在集合中找到下一个最高矩形并将点(current.finishX, new.y)
添加到输出(O(1)
)(如果集合为空,则将(current.finishX, 0)
添加到输出)李>
所以O(n log n)
。
【讨论】:
让我看看如果我理解正确,通过拆分您的意思的 x 坐标,例如,(2, 4, 8) -> (2, 4), (8, 0), 对? 抱歉,我不清楚您所说的“当前矩形”是什么意思。只是初始矩形的列表? 对不起,也许我太笨了,但我还是不明白。每当遇到 start 时:将其添加到矩形集合中,但我们刚刚确定这些结构不是矩形 @Oxymoron 您将对象的矩形成员添加到集合中。 如何“找到集合中的下一个最高矩形”O(1)?【参考方案2】:这可以通过修改归并排序算法来实现。天际线的算法如下:
构建天际线
ConstructSkyLine(List B ) --------------- O(nlogn)
If(B.size() == 1)
List skyLineList = new List();
SKYLINE = new SKYLINE(B.XL, B.XR, B.H);
skyLineList.add(SKYLINE);
Return skyLineList;
B1, B2 <-- Split(B);
List S1 <-- ConstructSkyLine(B1);
List S2 <-- ConstructSkyLine(B2);
List S <-- MergeSkyline(S1, S2);
Return S;
合并天际线
MergeSkyline(List S1, List S2) --------------- O(n)
List< SKYLINEENTRY> skylineEntryList = new ArrayList<SKYLINEENTRY>();
while (S1.isEmpty() && S2.isEmpty())--------------- O(n)
S1Item <-- S1.get(0);
S2Item <-- S2.get(0);
If (S1Item.XL < S2Item.XL)
Merge(S1, S2, skylineEntryList); --------------- O(n)
Else
Merge(S2, S1, skylineEntryList); --------------- O(n)
If(!S1.isEmpty())
skylineEntryList.add(S1);
If(!S2.isEmpty())
skylineEntryList.add(S2);
Retrun skylineEntryList;
合并
Merge(S1, S2, skylineEntryList) --------------- O(n)
SKYLINEENTRY <-- null;
S1Item <-- S1.get(0);
S2Item <-- S2.get(0);
SKYLINEENTRY.XL = S1Item.XL;
If(S1Item.XR > S2Item.XL) // means over lap
If(S1Item.H > S2Item.H) // S1 is higher.
SKYLINEENTRY.XR = S1Item.XR;
SKYLINEENTRY.H = S1Item.H;
S1.remove(S1Item); --------------- O(n)
skylineEntryList.add(SKYLINEENTRY);
if(S2Item.XR < S1Item.XR) // full overlap
S2.remove(S2Item); --------------- O(n)
Else // partial overlap
S2Item.XL <-- S1Item.XR;
Else //S2 is higher
SKYLINEENTRY.XR = S2Item.XL;
SKYLINEENTRY.H = S1Item.H;
if(S2Item.XR < S1Item.XR) // full overlap with S2
S1Item.XL = S2Item.XR;
Else // partial overlap
S1.remove(S1Item); --------------- O(n)
skylineEntryList.add(SKYLINEENTRY);
Else // no overlap
SKYLINEENTRY.XR = S1Item.XR;
SKYLINEENTRY.H = S1Item.H;
S1.remove(S1Item); --------------- O(n)
skylineEntryList.add(SKYLINEENTRY);
【讨论】:
以上是关于合并天际线,分而治之的主要内容,如果未能解决你的问题,请参考以下文章