让我们说我们得到4点形式的矩形:它们(x1,y1),...,(x4,y4) 我们想要计算它们所涵盖的总面积。我们想要计算总面积,如果更多的矩形重叠,我们只计算一次该区域。
我不是真的在寻找完整的解决方案,伪代码或一些有用的算法和数据结构的链接,我们将不胜感激。
矩形的形式是:由三个整数给出:左侧位置,右侧位置和高度。例如:
L:0 R:2 H:2
L:1 R:3 H:3
L:-1 R:4 H:1
总面积为:10
x轴的最大值是-1e9到1e9,从x = L开始,到x = R结束 y不能低于0并始终从y = 0开始并在y = H
处结束答案 0 :(得分:3)
让我们假设你的矩形在很小的范围内有整数坐标,比如0到10.然后一个简单的方法是创建一个网格并将矩形绘制到它上面:
占用的“像素”可以存储在一个集合中,或者它们可以在位图中设置位。当矩形重叠时,交叉点再次被标记为占用,因此仅对该区域贡献一次。该区域是占用单元的数量。
对于大尺寸,数据结构会变得太大。另外,绘制一个宽度为几百万像素的矩形会很慢。
但是当我们使用压缩坐标时,仍然可以应用该技术。那么你的网格只有坐标是矩形的实际坐标。细胞具有可变的宽度和高度。单元格的数量取决于矩形的数量,但它与最小和最大坐标无关:
算法如下所示:
答案 1 :(得分:1)
这些矩形的基数为y = 0?我认为这是真的。所以这些就像从远处看城市中的建筑物。你正试图追踪天际线。
将矩形存储在一个数组中,以便您可以将数组索引用作唯一ID。将每个左右矩形边缘表示为"事件"包括它所属矩形的ID和相应边的x坐标。将所有事件放在EL列表中并按x坐标排序。最后,您需要一个按相应矩形高度降序排序的矩形ID的动态排序集(例如Java TreeSet)。它被称为SL,"扫描线"。由于它的排序方式,SL.first始终是SL当前引用的最高矩形的ID。
现在您可以按如下方式绘制矩形集合的轮廓:
SL = <empty> // sweep line
x0 = EL.first.left // leftmost x among all rectangle edges
lastX = x0
for each event E in EL // process events left-to-right
Let y0 = if SL.isEmpty then 0 else SL.first.height // current y
if E.ID in SL // event in SL means sweep line is at rectangle's right edge
remove E.ID from SL
else // event means sweep line is a new rectangle's left edge
add E.ID to SL
Let y1 = if SL.isEmpty then 0 else SL.first.height // new y
if y1 != y0
output line seg (lastX, y0) -> (E.x, y0)
output line seg (E.x, y0) -> (E.x, y1)
lastX = E.x
output final line seg (lastX, 0) -> (x0, 0)
因为这听起来像是家庭作业或者是面试问题,我会让你修改这个算法来提供扫掠形状的区域,而不是画出它的边缘。
<强>加成强>
只是为了好玩:
import java.util.ArrayList;
import static java.lang.Integer.compare;
import static java.util.Arrays.stream;
import static java.util.Collections.sort;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
class SkyLine {
static class Rectangle {
final int left;
final int right;
final int height;
Rectangle(int left, int right, int height) {
this.left = left;
this.right = right;
this.height = height;
}
}
static class Event implements Comparable<Event> {
final int x;
final int id;
public Event(int x, int id) {
this.x = x;
this.id = id;
}
@Override
public int compareTo(Event e) { return compare(x, e.x); }
}
final List<Rectangle> rectangles = new ArrayList<>();
final Comparator byHeightDescending =
(Comparator<Integer>) (Integer a, Integer b) ->
compare(rectangles.get(b).height, rectangles.get(a).height);
final SortedSet<Integer> scanLine = new TreeSet<>(byHeightDescending);
final List<Event> events = new ArrayList<>();
SkyLine(Rectangle [] data) {
stream(data).forEach(rectangles::add);
int id = 0;
for (Rectangle r : rectangles) {
events.add(new Event(r.left, id));
events.add(new Event(r.right, id));
++id;
}
sort(events);
}
int area() {
int area = 0;
Event ePrev = null;
for (Event e : events) {
if (ePrev != null) area += (e.x - ePrev.x) * rectangles.get(scanLine.first()).height;
if (!scanLine.remove(e.id)) scanLine.add(e.id);
ePrev = e;
}
return area;
}
public static void main(String [] args) {
Rectangle [] data = {
new Rectangle(0, 2, 2),
new Rectangle(1, 3, 3),
new Rectangle(-1, 4, 1),
};
int area = new SkyLine(data).area();
System.out.println(area);
}
}