我已经在这个问题上工作了两天,我能做的最好的事情就是蛮力解决方案,效率不够。
您将获得一系列正坐标点,范围从(0, 0)
到(1 billion, 1 billion)
。您必须将所有点仅包含两个具有最小总面积的矩形。矩形必须具有平行于x轴和y轴的边。矩形不能重叠,共享相同的边界计数与重叠。您**can**
的{{1}}个0
矩形区域为零。两个矩形的面积之和为0
您还必须找到包含所有点的最小可能区域的单个矩形。此区域为**X**
您正试图找到**Y**
。
对于以下示例,答案为**Y** - **X**
。
**Y** - **X** = 107
非常感谢提供代码,如果您这样做,请尽可能使用Java或C ++。
答案 0 :(得分:4)
我不想破坏游戏。
从大矩形开始。然后你可以分割点的每个x或y。
按x对点进行一次排序,一次按y。
垂直拆分:
#######
#######
#######
#######
水平分割:
##
## ####
####
####
在坐标处分割产生两组点,其中两个矩形半部都很容易缩小。
因评论而添加了解决方案
作为Point类,我实际使用int[2]
,因此x / y选项可以作为for-index。另一方面,我必须创建一个类AreaCollector,其中一个简单的Rectangle就足够了。
我收集的矩形点也是;如果没有它们,代码就会变得更小。
static private class AreaCollector {
private final int[] lwb = new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE };
private final int[] upb = new int[] { Integer.MIN_VALUE, Integer.MIN_VALUE };
public void add(int[] point) {
if (point[0] < lwb[0]) {
lwb[0] = point[0];
}
if (point[1] < lwb[1]) {
lwb[1] = point[1];
}
if (point[0] > upb[0]) {
upb[0] = point[0];
}
if (point[1] > upb[1]) {
upb[1] = point[1];
}
}
public int getArea() {
if (upb[0] == Integer.MIN_VALUE) { /// Zero points added.
return 0;
}
return (upb[0] - lwb[0]) * (upb[1] - lwb[1]);
}
}
public int solve(int[][] points) {
AreaCollector ac = new AreaCollector();
for (int[] point : points) {
ac.add(point);
}
final int y = ac.getArea();
final int n = points.length;
// Best solution sofar:
int[][] ascPoints = Arrays.copyOf(points, n);
int[][] descPoints = new int[0][];
int bestX = y + 0;
for (int direction = 0; direction < 2; ++direction) {
final int dir = direction;
Arrays.sort(points, Comparator.comparingInt((pt) -> pt[dir]));
int[] ascAreas = new int[n];
AreaCollector ascAC = new AreaCollector();
for (int i = 0; i < n; ) {
int[] point = points[i];
int coord = point[direction];
for (int j = i; j < n && points[j][direction] == coord; ++j) {
ascAC.add(points[j]);
}
int area = ascAC.getArea();
for (int j = i; j < n && points[j][direction] == coord; ++j) {
ascAreas[j] = area;
++i;
}
}
int[] descAreas = new int[n];
AreaCollector descAC = new AreaCollector();
for (int i = n - 1; i >= 0; ) {
int[] point = points[i];
int coord = point[direction];
for (int j = i; j >= 0 && points[j][direction] == coord; --j) {
descAC.add(points[j]);
}
int area = descAC.getArea();
for (int j = i; j >= 0 && points[j][direction] == coord; --j) {
descAreas[j] = area;
--i;
}
}
int bestI = -1;
for (int i = 0; i < n- 1; ++i) {
if (points[i][direction] != points[i + 1][direction]) {
int x = ascAreas[i] + descAreas[i + 1];
if (x < bestX) {
bestX = x;
bestI = i;
}
}
}
if (bestI != -1) {
ascPoints = Arrays.copyOfRange(points, 0, bestI + 1);
descPoints = Arrays.copyOfRange(points, bestI + 1, n);
}
}
return y -bestX;
}
作为比较器,我使用了java 8简洁表示法。如您所见,手动编码部分的复杂性为O(N),取代Arrays.sort
O(N.log N)。
答案 1 :(得分:3)
这是Java的解决方案。在计算区域Y之后,它首先按X坐标对坐标进行排序,然后通过在每个X坐标处将数组分成两半来计算矩形的面积(如果两个坐标具有相同的X值,则进行特殊处理)。然后它为Y坐标做同样的事情。最小矩形区域是生成的X区域。
import java.util.Arrays;
import java.util.Comparator;
public class Puzzle {
public static void main(String[] args) {
int[][] COORDINATES_1 = { { 4, 2 }, { 8, 10 }, { 1, 1 }, { 9, 12 }, { 14, 7 }, { 2, 3 } };
int[][] COORDINATES_2 = { { 2, 1 }, { 2, 2 }, { 3, 1 }, { 3, 3 }, { 4, 3 }, { 5, 3 }, { 5, 4 }, { 6, 4 } };
int[][] COORDINATES_3 = { { 4, 2 } };
solve(COORDINATES_1);
solve(COORDINATES_2);
solve(COORDINATES_3);
}
public static void solve(int[][] coordinates) {
int size = coordinates.length;
int y = calcMinRectArea(coordinates, 0, size);
// sort by x coordinates
Arrays.sort(coordinates, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
});
int x = y;
for (int i = 1; i < size; i++) {
if (coordinates[i][0] == coordinates[i - 1][0])
continue; // several coordinates with the same x coordinates
x = Math.min(calcMinRectArea(coordinates, 0, i) + calcMinRectArea(coordinates, i, size - i), x);
}
// sort by y coordinates
Arrays.sort(coordinates, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
for (int i = 1; i < size; i++) {
if (coordinates[i][1] == coordinates[i - 1][1])
continue; // several coordinates with the same y coordinates
x = Math.min(calcMinRectArea(coordinates, 0, i) + calcMinRectArea(coordinates, i, size - i), x);
}
System.out.printf("Y = %d, X = %d, Y - X = %d\n", y, x, y - x);
}
private static int calcMinRectArea(int[][] coords, int start, int length) {
if (length == 0)
return 0;
int minX = coords[start][0];
int maxX = minX;
int minY = coords[start][1];
int maxY = minY;
for (int i = start + 1; i < start + length; i++) {
int x = coords[i][0];
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
int y = coords[i][1];
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
}
return (maxX - minX) * (maxY - minY);
}
}