Algorithm 在给定一组线段的情况下查找面积最大的矩形
假设我给了你一组线段,形式是Algorithm 在给定一组线段的情况下查找面积最大的矩形,algorithm,data-structures,time-complexity,big-o,dynamic-programming,Algorithm,Data Structures,Time Complexity,Big O,Dynamic Programming,假设我给了你一组线段,形式是[(x1,y1),(x2,y2)]。我们有两个点定义了线段。出于我们的目的,该部分将始终是水平或垂直的。我想找到由线段包围的任何矩形的最大面积 例如,当给定以下线段集时,结果应为绿色阴影区域的面积: 到目前为止,我能想到的唯一解决方案是蛮力——每一对水平段(O(N^2))都要在运行时用每一对垂直段(O(N^2))进行检查。显然,我们可以通过预先计算哪些段可以放在一起来优化这一点,但这仍然会使时间复杂度保持在O(N^4) 我正在寻找理想的O(N^2)解决方案,但如果您
[(x1,y1),(x2,y2)]
。我们有两个点定义了线段。出于我们的目的,该部分将始终是水平或垂直的。我想找到由线段包围的任何矩形的最大面积
例如,当给定以下线段集时,结果应为绿色阴影区域的面积:
到目前为止,我能想到的唯一解决方案是蛮力——每一对水平段(O(N^2)
)都要在运行时用每一对垂直段(O(N^2)
)进行检查。显然,我们可以通过预先计算哪些段可以放在一起来优化这一点,但这仍然会使时间复杂度保持在O(N^4)
我正在寻找理想的
O(N^2)
解决方案,但如果您有任何小于O(N^4)
的解决方案,请与我们分享 您可以通过扫描找到垂直线和水平线之间的所有交点。按y递增的顺序遍历所有行。维护一个包含所有垂直线(包括当前y值)的缓冲区。保持缓冲区按每个垂直线的x值排序。当您到达每个水平线时,检查它是否与缓冲区中的任何线相交。最坏的情况是当有O(N^2)个交叉口时
现在您有了一个交叉点列表,以及每条线的交叉点列表。对于每一条水平线,对于每一个交叉点,我们感兴趣的是沿着该交叉点的垂直线可以走多远。将这些值存储在数组中。将这些值分成几对,并在数组中存储每对的最大值。对每个最大值重复此过程,依此类推。这将构建一个值树,其中叶是原始值,按原始顺序排列,每个节点都具有在任何子代中找到的最大值。总成本与交叉口数量成线性关系
现在取每个交点,假设它是矩形的左下角。对于其垂直线上的每个交点,查看相交的水平线,并找到该线上最右侧的点,在该点上,您可以向下至少到达交点。您已经构建了一棵树,它允许您在该直线上的交点数中找到该时间对数:从树的顶部开始,如果该子节点的值至少达到您需要的距离,则向右移动,否则向左移动。通过左下角和水平线查找此项,可以得到最大的矩形,因此对每条水平线检查此项,可以得到最大的矩形,包括左下角的交点,对每个交点重复此项,可以得到整体最大的矩形
如果这些线形成了一个nxn网格,那么对于每个交叉点,您将检查其上方的O(N)条水平线,成本为O(logn),因此在最坏的情况下,该阶段的总成本为O(N^3logn)。您提供的示例: 实际上,一旦我们只提取和合并由交点形成的矩形,就会简化为这样:
---------------------
| |
| |
| |
| |
--------- ------------------
| |
|____________________________|
然后问题就变成了在直线(又称正交)多边形中寻找最大的矩形,关于这个问题有很多文献。你可以使用直线扫描算法来解决这个问题。
在这种情况下,向上移动时,垂直线将从线集中添加或删除。线的起点和终点都将添加到扫掠集,水平线也将添加到列表中。
- 步骤1:将线添加到activeVertical
- 步骤2:添加到activeVertical的第二行
- 步骤3:添加到activeVertical的第三行(注意:它们按X的顺序排列)李>
- 步骤4a:添加到activeVertical的第四行
- 第4b步:找到水平线,是时候创建一个不包含水平线的矩形了 有身高吗
- 第5步:找到第二条水平线,检查完成上一个矩形的时间
使用系统;
使用System.Collections.Generic;
使用System.Linq;
名称空间tt
{
公共课点
{
公共点(双X,双Y)
{
这个.X=X;
这个。Y=Y;
}
公共双X{get;set;}
公共双Y{get;set;}
}
公共班级线
{
公共点开始{get;set;}
公共点结束{get;set;}
}
公共类矩形
{
公共矩形()
{ }
公共矩形(点左下角,点右上角)
{
this.BottomLeft=BottomLeft;
this.TopRight=TopRight;
}
公共点左下角{get;set;}
公共点右上方{get;set;}
}
公共类X比较者:I比较者
{
公共整数比较(x行,y行)
{
返回x.Start.x.CompareTo(y.Start.x);
}
}
公共课程
{
公共静态int GetMinIndex(列表行、水平行)
{
var xComp=new XComparer();
int minIndex=Lines.BinarySearch(水平,xComp);
如果(minIndex<0)minIndex=~minIndex;
返回minIndex;
}
公共静态int GetMaxIndex(列表行,水平行)
{
var xComp=new XComparer();
int maxIndex=Lines.BinarySearch(新行(){Start=Horizontal.End},xComp);
如果(maxIndex<0)maxIndex=~maxIndex-1;
返回最大索引;
}
公共静态void Main()
{
列表行=新列表();
Add(newline(){Start=newpoint(0.5,12.5),End=newpoint(10,12.5)});
添加(新行(){开始=新点(2.5,9.5),结束=新点,
using System;
using System.Collections.Generic;
using System.Linq;
namespace tt
{
public class Point
{
public Point(double X, double Y)
{
this.X = X;
this.Y = Y;
}
public double X { get; set; }
public double Y { get; set; }
}
public class Line
{
public Point Start { get; set; }
public Point End { get; set; }
}
public class Rectangle
{
public Rectangle()
{ }
public Rectangle(Point BottomLeft, Point TopRight)
{
this.BottomLeft = BottomLeft;
this.TopRight = TopRight;
}
public Point BottomLeft { get; set; }
public Point TopRight { get; set; }
}
public class XComparer : IComparer<Line>
{
public int Compare(Line x, Line y)
{
return x.Start.X.CompareTo(y.Start.X);
}
}
public class Program
{
public static int GetMinIndex(List<Line> Lines, Line Horizontal)
{
var xComp = new XComparer();
int minIndex = Lines.BinarySearch(Horizontal, xComp);
if (minIndex < 0) minIndex = ~minIndex;
return minIndex;
}
public static int GetMaxIndex(List<Line> Lines, Line Horizontal)
{
var xComp = new XComparer();
int maxIndex = Lines.BinarySearch(new Line() { Start = Horizontal.End }, xComp);
if (maxIndex < 0) maxIndex = ~maxIndex - 1;
return maxIndex;
}
public static void Main()
{
List<Line> lines = new List<Line>();
lines.Add(new Line() { Start = new Point(0.5, 12.5), End = new Point(10, 12.5) });
lines.Add(new Line() { Start = new Point(2.5, 9.5), End = new Point(15.8, 9.5) });
lines.Add(new Line() { Start = new Point(6, 8.5), End = new Point(16.3, 8.5) });
lines.Add(new Line() { Start = new Point(3.5, 8.5), End = new Point(3.5, 12.5) });
lines.Add(new Line() { Start = new Point(7, 4.2), End = new Point(7, 13.8) });
lines.Add(new Line() { Start = new Point(10, 5.8), End = new Point(10, 14.2) });
lines.Add(new Line() { Start = new Point(15.6, 0), End = new Point(15.6, 16) });
lines.Add(new Line() { Start = new Point(1.6, 20), End = new Point(15.6, 20) });
var activeVertical = new List<Line>();
SortedList<double, List<Line>> sweepSet = new SortedList<double, List<Line>>();
foreach (Line oneLine in lines.Where(x => x.Start.X == x.End.X))
{
if (!sweepSet.ContainsKey(oneLine.Start.Y)) sweepSet.Add(oneLine.Start.Y, new List<Line>());
sweepSet[oneLine.Start.Y].Add(oneLine);
if (!sweepSet.ContainsKey(oneLine.End.Y)) sweepSet.Add(oneLine.End.Y, new List<Line>());
sweepSet[oneLine.End.Y].Add(oneLine);
}
var linesHorizontal = lines.Where(x => x.Start.Y == x.End.Y).OrderBy(x => x.Start.Y).ToList();
List<Rectangle> rectangles = new List<Rectangle>();
List<Rectangle> completedRectangles = new List<Rectangle>();
var xComp = new XComparer();
int horIndex = 0;
int sweepIndex = 0;
while (sweepIndex < sweepSet.Count)
{
double y = Math.Min(sweepSet.Keys[sweepIndex], linesHorizontal[horIndex].Start.Y);
double verValue = linesHorizontal[horIndex].Start.Y;
//add lines which are influencing
if (sweepSet.ContainsKey(y))
{
foreach (Line oneLine in sweepSet[y].Where(x => x.Start.Y == y))
{
int index = activeVertical.BinarySearch(oneLine, xComp);
if (index < 0) index = ~index;
activeVertical.Insert(index, oneLine);
}
}
if (y == verValue)
{
int minIndex = GetMinIndex(activeVertical, linesHorizontal[horIndex]);
int maxIndex = GetMaxIndex(activeVertical, linesHorizontal[horIndex]);
if (minIndex != maxIndex && minIndex < activeVertical.Count && maxIndex < activeVertical.Count)
{
double minX = activeVertical[minIndex].Start.X;
double maxX = activeVertical[maxIndex].Start.X;
foreach (Rectangle oneRec in rectangles)
{
if (minX > oneRec.BottomLeft.X) oneRec.BottomLeft.X = minX;
if (maxX < oneRec.TopRight.X) oneRec.TopRight.X = maxX;
oneRec.TopRight.Y = verValue;
}
completedRectangles.AddRange(rectangles);
rectangles.Clear();
rectangles.Add(new Rectangle(new Point(activeVertical[minIndex].Start.X, verValue), new Point(activeVertical[maxIndex].Start.X, verValue)));
}
else rectangles.Clear();
}
//Cleanup lines which end
if (sweepSet.ContainsKey(y))
{
foreach (Line oneLine in sweepSet[y].Where(x => x.End.Y == y))
{
activeVertical.Remove(oneLine);
}
}
if (y >= verValue)
{
horIndex++;
if (horIndex == linesHorizontal.Count) break;
if (y == sweepSet.Keys[sweepIndex]) sweepIndex++;
}
else
{
sweepIndex++;
}
}
}
}