题目
Given a set of points in the xy-plane, determine the minimum area of a rectangle formed from these points, with sides parallel to the x and y axes.
If there isn’t any rectangle, return 0.
Example 1:
Input: [[1,1],[1,3],[3,1],[3,3],[2,2]]
Output: 4
Example 2:
Input: [[1,1],[1,3],[3,1],[3,3],[4,1],[4,3]]
Output: 2
Note:
- 1 <= points.length <= 500
- 0 <= points[i][0] <= 40000
- 0 <= points[i][1] <= 40000
- All points are distinct.
题目大意
从给出的点中选出4个点组成 矩形,使得矩形的面积最小。
思路
很多问题都是相似的,换句话说就是建立的模型是相同的。
这道题的模型近似 sum求和问题。也是找组合问题。
找出一个 组合,该组合满足一定的要求。
思路1: 固定3个点找一个点。这里 固定 矩形的左下,左上, 右下点 找 右上点。
思路1的方法:
time o(n3) 将 所有点放入 set中,固定 左下,左上, 右下点 计算出 右上点。 判断该点是否在 set中。但时间复杂度太高,不能过。且 int[] 不能作为 map的key 与 set 值放入(只会记录 地址值)。
有两个方法解决 int[] 问题:
- 将 int[] 转为 String,在每个元素转成字符串,每个元素之间用 “#”分隔。
- 使用Pair 类
class Solution {
public int minAreaRect(int[][] points) {
Set<String> set = new HashSet<>();
for(int [] point :points)
set.add(String.valueOf(point[0])+'#'+String.valueOf(point[1]));
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0]!=0?o1[0] - o2[0]:o1[1]-o2[1];
}
});
int res = Integer.MAX_VALUE;
for(int i = 0 ;i < points.length;i++){
for(int j = i+1;j<points.length;j++){
if(points[i][0]!=points[j][0])
continue;
for(int k = j+1;k<points.length;k++){
if(points[i][1]!=points[k][1])
continue;
int[] pl = new int[]{points[k][0],points[j][1]};
if(set.contains(String.valueOf(pl[0])+'#'+String.valueOf(pl[1]))){
res = Math.min(res,(pl[0]-points[i][0])*(pl[1] - points[i][1]));
}
}
}
}
return res != Integer.MAX_VALUE?res:0;
}
}
对上述代码进行优化,使得查找 左上, 右下点 更快, 但还是超时。
class Solution {
public String pointToString(int[] point){
return String.valueOf(point[0])+"#"+ String.valueOf(point[1]);
}
public int minAreaRect(int[][] points) {
Set<String> set = new HashSet<>();
for (int[] point : points)
set.add(pointToString(point));
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0] != 0 ? o1[0] - o2[0] : o1[1] - o2[1];
}
});
int res = Integer.MAX_VALUE;
for (int i = 0; i < points.length; i++) {
int[] p0 = points[i];
for (int j = i + 2; j < points.length; j++) {
int[] p3 = points[j];
if(!(p0[0]<p3[0]&&p0[1]<p3[1]))
continue;
int[] p1 = {p0[0], p3[1]};
int[] p2 = {p3[0], p0[1]};
if (set.contains(pointToString(p1)) && set.contains(pointToString(p2)))
res = Math.min(res, (p3[0] - p0[0]) * (p3[1] - p0[1]));
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
思路2: 固定2个点找2个点。这里 固定 矩形的左下、右上点找 左上, 右下点。固定 左下、右上点 可以计算 左上, 右下点 ,看这两个点是否在 set中。
思路2的方法:
对points 进行排序,使得左下 在 右上点之前。
在points 遍历 左下点,过两个点 后将该点作为 候选 右下点,若该点的 横纵坐标都应大于 左下点。计算出 相应的 左上, 右下点,若这两点均在set(points)中,那么这四个点可以组成一个矩形。
使用string 放入 set中。
class Solution {
public String pointToString(int[] point){
return String.valueOf(point[0])+"#"+ String.valueOf(point[1]);
}
public int minAreaRect(int[][] points) {
Set<String> set = new HashSet<>();
for (int[] point : points)
set.add(pointToString(point));
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0] != 0 ? o1[0] - o2[0] : o1[1] - o2[1];
}
});
int res = Integer.MAX_VALUE;
for (int i = 0; i < points.length; i++) {
int[] p0 = points[i];
for (int j = i + 2; j < points.length; j++) {
int[] p3 = points[j];
if(!(p0[0]<p3[0]&&p0[1]<p3[1]))
continue;
int[] p1 = {p0[0], p3[1]};
int[] p2 = {p3[0], p0[1]};
if (set.contains(pointToString(p1)) && set.contains(pointToString(p2)))
res = Math.min(res, (p3[0] - p0[0]) * (p3[1] - p0[1]));
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
使用 Pair放入set中
import javafx.util.Pair;
class Solution {
public int minAreaRect(int[][] points) {
Set<Pair<Integer, Integer>> set = new HashSet<>();
for (int[] point : points)
set.add(new Pair<Integer,Integer>(point[0],point[1]));
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0] != 0 ? o1[0] - o2[0] : o1[1] - o2[1];
}
});
int res = Integer.MAX_VALUE;
for (int i = 0; i < points.length; i++) {
int[] p0 = points[i];
for (int j = i + 2; j < points.length; j++) {
int[] p3 = points[j];
if(!(p0[0]<p3[0]&&p0[1]<p3[1]))
continue;
int[] p1 = {p0[0], p3[1]};
int[] p2 = {p3[0], p0[1]};
if (set.contains(new Pair<Integer,Integer>(p1[0],p1[1])) && set.contains(new Pair<Integer,Integer>(p2[0],p2[1])))
res = Math.min(res, (p3[0] - p0[0]) * (p3[1] - p0[1]));
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}