[LeetCode] 939. Minimum Area Rectangle My SubmissionsBack to Contest

本文解析了LeetCode周赛110的一道题目,目标是在给定点集中找到最小面积的矩形,详细介绍了两种解题思路及代码实现,包括固定三点找第四点和固定两点找另两点的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题:https://leetcode.com/contest/weekly-contest-110/problems/minimum-area-rectangle/

题目

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. 1 <= points.length <= 500
  2. 0 <= points[i][0] <= 40000
  3. 0 <= points[i][1] <= 40000
  4. All points are distinct.

题目大意

从给出的点中选出4个点组成 矩形,使得矩形的面积最小。

思路

很多问题都是相似的,换句话说就是建立的模型是相同的。

这道题的模型近似 sum求和问题。也是找组合问题。
找出一个 组合,该组合满足一定的要求。

思路1: 固定3个点找一个点。这里 固定 矩形的左下,左上, 右下点 找 右上点。

思路1的方法:

time o(n3) 将 所有点放入 set中,固定 左下,左上, 右下点 计算出 右上点。 判断该点是否在 set中。但时间复杂度太高,不能过。且 int[] 不能作为 map的key 与 set 值放入(只会记录 地址值)。

有两个方法解决 int[] 问题:

  1. 将 int[] 转为 String,在每个元素转成字符串,每个元素之间用 “#”分隔。
  2. 使用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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值