Leetcode 939:最小面积矩形(最详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/84102001

给定在 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. 1 <= points.length <= 500
  2. 0 <= points[i][0] <= 40000
  3. 0 <= points[i][1] <= 40000
  4. 所有的点都是不同的。

解题思路

首先做一些准备工作。我们知道如果所有的点在同一行或者同一列上,那么我们就没有解。

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轴的平行线,然后在这些平行线中找间隔最小的平行于xy轴的平行线,将这两个间隔相乘即为最小面积。

首先我们先要遍历全部的point,然后将所有相同的x轴的点加入到一个list中,由于横坐标的数量不定,所以我们选用defaultdict去存放所有的list

1:1, 3
3:3, 1
2:2

注意,因为python没有自带ordered_setordered_map这两种结构,所有我们要对上述的dict和所有的list先排序,然后再从左到右从下到上遍历所有的直线。我们首先采取的策略是,先从所有的横坐标中选取出两个,然后取这两个横坐标对应的纵坐标的交集,然后从交集中选取两个元素,最后就是取横坐标差乘以纵坐标差的最小值。

扫描二维码关注公众号,回复: 4090993 查看本文章
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

https://leetcode.com/problems/minimum-area-rectangle/discuss/192026/C++-hash-map-+-set-intersection-56-ms

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/84102001