给定在 xy 平面上的一组点,确定由这些点组成的矩形的最小面积,其中矩形的边平行于 x 轴和 y 轴。
如果没有任何矩形,就返回 0。
示例 1:
输入:[[1,1],[1,3],[3,1],[3,3],[2,2]]
输出:4
示例 2:
输入:[[1,1],[1,3],[3,1],[3,3],[4,1],[4,3]]
输出:2
提示:
1 <= points.length <= 500
0 <= points[i][0] <= 40000
0 <= points[i][1] <= 40000
- 所有的点都是不同的。
解题思路
首先做一些准备工作。我们知道如果所有的点在同一行或者同一列上,那么我们就没有解。
n = len(points)
nx = len(set(x for x, y in points))
ny = len(set(y for x, y in points))
if nx == n or ny == n:
return 0
我们首先想到的解法就是暴力破解,首先遍历points
,从中选出第一个访问点[x1,y1]
,将所有访问过的[x1,y1]
添加到一个set
中,,我们每次从set
中选出第二个点[x2,y2]
(也就是先确定对角线上的点),然后判断[x1,y2]
和[x2,y1]
是不是在set
中,这样我们就可以判断出是否存在由[x1,y1]->[x2,y2]
形成的矩形。最后取所有面积的最小值即可。
class Solution:
def minAreaRect(self, points):
"""
:type points: List[List[int]]
:rtype: int
"""
mem = set()
result = float("inf")
for x1, y1 in points:
for x2, y2 in mem:
if (x1, y2) in mem and (x2, y1) in mem:
area = abs(x1 - x2)*abs(y1 - y2)
if area and area < result:
result = area
mem.add((x1, y1))
return result if result != float("inf") else 0
另外我们也可以想到这样的思路,就是找平行于x
轴和平行于y
轴的平行线,然后在这些平行线中找间隔最小的平行于x
和y
轴的平行线,将这两个间隔相乘即为最小面积。
首先我们先要遍历全部的point
,然后将所有相同的x
轴的点加入到一个list
中,由于横坐标的数量不定,所以我们选用defaultdict
去存放所有的list
1:1, 3
3:3, 1
2:2
注意,因为python
没有自带ordered_set
和ordered_map
这两种结构,所有我们要对上述的dict
和所有的list
先排序,然后再从左到右从下到上遍历所有的直线。我们首先采取的策略是,先从所有的横坐标中选取出两个,然后取这两个横坐标对应的纵坐标的交集,然后从交集中选取两个元素,最后就是取横坐标差乘以纵坐标差的最小值。
from collections import defaultdict
class Solution:
def minAreaRect(self, points):
"""
:type points: List[List[int]]
:rtype: int
"""
columns = defaultdict(set)
for x, y in points:
columns[x].add(y)
result = float('inf')
columns_keys_list = list(columns.keys())
for i, x1 in enumerate(columns_keys_list):
for x2 in columns_keys_list[i+1:]:
y = sorted(list(columns[x1] & columns[x2]))
for i in range(1,len(y)):
result = min(result, abs(x1 - x2)*abs(y[i] - y[i-1]))
return result if result != float('inf') else 0
另外一种思路是遍历所有的横坐标,例如当我们遍历到x
时,我们再遍历想x
对应的所有纵坐标,从纵坐标中选出y1,y2
看我们之前访问过的横坐标中是否有相同的纵坐标,如果有的话,那么我们就可以构成矩形,我们计算此时矩形的面积,接着我们将y1,y2
添加到访问记录中。
这样做法的好处在于,我们的访问记录可以使用set
这种结构,这样我们在查找的时候就会非常迅速。
from collections import defaultdict
class Solution:
def minAreaRect(self, points):
"""
:type points: List[List[int]]
:rtype: int
"""
columns = defaultdict(list)
for x, y in points:
columns[x].append(y)
seen, result = {}, float('inf')
for x2 in sorted(columns):
column = columns[x2]
column.sort()
for j, y2 in enumerate(column):
for i in range(j):
y1 = column[i]
if (y1, y2) in seen:
result = min(result, (x2 - seen[y1,y2]) * (y2 - y1))
seen[y1, y2] = x2
return result if result != float('inf') else 0
不过这个代码使用c++
实现相当不容易。
reference:
https://leetcode.com/problems/minimum-area-rectangle/discuss/192021/Python-O(N1.5)-80ms
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!