963 最小面积矩形 II(数学-判断是否四个点能否构成矩形)

44 篇文章 1 订阅
本文探讨了一种算法,如何利用Python解决在二维坐标系中,给定一组不规则点,寻找由这些点构成的具有最小面积的矩形问题。介绍了两种不同的思路,包括通过判断平行四边形和对角线垂直,以及利用中心点和距离一致的特性。代码实例展示了如何运用复数和字典数据结构优化解决方案。
摘要由CSDN通过智能技术生成

1. 问题描述:

给定在 xy 平面上的一组点,确定由这些点组成的任何矩形的最小面积,其中矩形的边不一定平行于 x 轴和 y 轴。如果没有任何矩形,就返回 0。

示例 1:

输入:[[1,2],[2,1],[1,0],[0,1]]
输出:2.00000
解释:最小面积的矩形出现在 [1,2],[2,1],[1,0],[0,1] 处,面积为 2。

示例 2:

输入:[[0,1],[2,1],[1,1],[1,0],[2,0]]
输出:1.00000
解释:最小面积的矩形出现在 [1,0],[1,1],[2,1],[2,0] 处,面积为 1。

示例 3:

输入:[[0,3],[1,2],[3,1],[1,3],[2,1]]
输出:0
解释:没法从这些点中组成任何矩形。

示例 4:

输入:[[3,1],[1,1],[0,1],[2,1],[3,3],[3,2],[0,2],[2,3]]
输出:2.00000
解释:最小面积的矩形出现在 [2,1],[2,3],[3,3],[3,1] 处,面积为 2。

提示:

1 <= points.length <= 50
0 <= points[i][0] <= 40000
0 <= points[i][1] <= 40000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-area-rectangle-ii

2. 思路分析:

① 一开始的时候是没有什么思路,理解了一下官方的题解,官方提供了两种思路。第一种思路:先判断四个点是否能够构成平行四边形,然后再判断平行四边形中的相邻两条边是否垂直,具体的做法是任意取出points列表中的三个点p1,p2,p3(因为使用的是python语言所以可以使用itertools.permutations方法得到points集合中长度为3的所有排列),然后检查以p2,p3为顶点的对角线中的另外一条对角线中的第四个顶点p4是否存在,其实是判断对角线是否相等,使用x1 + x2 == x3 + x4,y1 + y2 == y3 + y4进行判断,同时满足这两个条件才可以判断两条对角线相等,具体的做法是判断p4 = p2 + p3 - p1是否存在于points列表中,假如存在再判断相邻的两条边是否垂直,当使用坐标来判断是否是垂直的时候可以使用:x1 * x2 + y1 * y2 == 0,因为在求解的时候可能存在误差,所以规定在一定误差范围之内的都是符合答案的,所以我们使用x1 * x2 + y1 * y2小于某一个误差的时候肯定是满足答案的(x1 * x2 + y1 * y2 == 0的时候就垂直了)

② 第二种思路是根据矩形的充分必要条件进行判定的:两条对角线的中心相同并且顶点到中心的距离也是相等的,所以需要维护两个变量:两个顶点的中心以及顶点到中心的距离,具体的做法是任意取出points点集中的两个元素计算他们的中心以及顶点到中心的距离,并且将其映射在一个字典中,只有同时存在中心点相同而且顶点到中心点的距离是一样的才会被映射到同一个位置,最终我们可以遍历这个字典取出同时满足这两个条件的组合,相邻两个顶点之间的距离相乘那么就为矩形的面积

③ 官方的第二种思路中字典将一个复数以及float类型的值作为键还是第一次看到,值得学习学习

3. 代码如下:

官方代码如下:

import collections
import itertools


class Solution(object):
    def minAreaFreeRect(self, points):
        EPS = 1e-7
        points = set(map(tuple, points))
        ans = float('inf')
        for p1, p2, p3 in itertools.permutations(points, 3):
            print(p1, p2, p3)
            p4 = p2[0] + p3[0] - p1[0], p2[1] + p3[1] - p1[1]
            if p4 in points:
                # 转化为复数进行求解
                v21 = complex(p2[0] - p1[0], p2[1] - p1[1])
                v31 = complex(p3[0] - p1[0], p3[1] - p1[1])
                if abs(v21.real * v31.real + v21.imag * v31.imag) < EPS:
                    area = abs(v21) * abs(v31)
                    if area < ans:
                        ans = area
        return ans if ans < float('inf') else 0
class Solution(object):
    def minAreaFreeRect(self, points):
        # 坐标点转换为复数之后那么对两个坐标点做差得到的就是两个坐标点之间的距离
        points = [complex(*z) for z in points]
        seen = collections.defaultdict(list)
        for P, Q in itertools.combinations(points, 2):
            center = (P + Q) / 2
            radius = abs(center - P)
            seen[center, radius].append(P)
        ans = float("inf")
        for (center, radius), candidates in seen.iteritems():
            for P, Q in itertools.combinations(candidates, 2):
                # 与Q对应的另外一个对角线上的顶点为2*center - Q: 之前计算center的时候取得就是两个点之间的中心, 所以使用这个公式就可以计算得到另外一个坐标的位置
                ans = min(ans, abs(P - Q) * abs(P - (2*center - Q)))
        return ans if ans < float("inf") else 0

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值