当前位置: 首页 > news >正文

LeetCode 391:完美矩形

LeetCode 391:完美矩形

在这里插入图片描述

问题本质:精确覆盖的两个核心条件

给定若干轴对齐的小矩形,判断它们是否能恰好覆盖一个大矩形(无重叠、无间隙)。需满足:

  1. 面积守恒:所有小矩形的面积和等于大矩形的面积。
  2. 顶点唯一:除大矩形的4个顶点外,其他顶点必须出现偶数次(重叠时顶点会被覆盖两次,间隙则会导致顶点缺失)。

核心思路:面积 + 顶点统计

1. 面积校验
  • 遍历所有小矩形,计算 大矩形的边界(最小左边界 left、最小下边界 bottom、最大右边界 right、最大上边界 top)。
  • 计算 小矩形总面积大矩形面积,若不相等,直接返回 false(存在间隙)。
2. 顶点校验
  • 用哈希表统计所有小矩形的 4个顶点(左下、左上、右下、右上)的出现次数。
  • 大矩形的4个顶点必须仅出现1次(唯一角),其余顶点必须出现偶数次(重叠抵消)。

算法步骤详解

步骤 1:计算大矩形边界与面积
int left = Integer.MAX_VALUE;   // 初始为极大值,确保被更新
int bottom = Integer.MAX_VALUE; 
int right = Integer.MIN_VALUE;  // 初始为极小值,确保被更新
int top = Integer.MIN_VALUE;    
long sumArea = 0;               // 小矩形总面积for (int[] rect : rectangles) {int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];// 更新大矩形边界left = Math.min(left, x1);bottom = Math.min(bottom, y1);right = Math.max(right, x2);top = Math.max(top, y2);// 累加小矩形面积sumArea += (long)(x2 - x1) * (y2 - y1);
}// 大矩形面积
long totalArea = (long)(right - left) * (top - bottom);
if (sumArea != totalArea) {return false; // 面积不等,直接失败
}
步骤 2:统计顶点出现次数

用哈希表记录每个顶点的出现次数(顶点用 (x, y) 唯一标识,通过位运算转换为 long 键):

Map<Long, Integer> pointCount = new HashMap<>();for (int[] rect : rectangles) {int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];// 四个顶点:左下、左上、右下、右上addPoint(pointCount, x1, y1);addPoint(pointCount, x1, y2);addPoint(pointCount, x2, y1);addPoint(pointCount, x2, y2);
}// 辅助方法:将(x,y)转换为唯一long键
private long getKey(int x, int y) {return (long)x << 32 | (y & 0xFFFFFFFFL); // x左移32位,y存低32位
}// 辅助方法:更新顶点计数
private void addPoint(Map<Long, Integer> map, int x, int y) {long key = getKey(x, y);map.put(key, map.getOrDefault(key, 0) + 1);
}
步骤 3:校验顶点规则
  1. 大矩形的4个顶点必须仅出现1次

    int[][] corners = {{left, bottom},  // 左下{left, top},     // 左上{right, bottom}, // 右下{right, top}     // 右上
    };for (int[] corner : corners) {int x = corner[0], y = corner[1];long key = getKey(x, y);Integer cnt = pointCount.get(key);if (cnt == null || cnt != 1) {return false; // 顶点不存在或次数不对}pointCount.put(key, cnt - 1); // 次数减为0(后续统一校验偶数)
    }
    
  2. 所有顶点次数必须为偶数(包括大矩形顶点减为0的情况):

    for (int count : pointCount.values()) {if (count % 2 != 0) {return false; // 存在奇数次顶点,说明重叠或缺失}
    }
    

完整代码(Java)

import java.util.HashMap;
import java.util.Map;class Solution {public boolean isRectangleCover(int[][] rectangles) {if (rectangles == null || rectangles.length == 0) {return false;}// 步骤1:计算大矩形的边界和总面积int left = Integer.MAX_VALUE;int bottom = Integer.MAX_VALUE;int right = Integer.MIN_VALUE;int top = Integer.MIN_VALUE;long sumArea = 0;for (int[] rect : rectangles) {int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];left = Math.min(left, x1);bottom = Math.min(bottom, y1);right = Math.max(right, x2);top = Math.max(top, y2);sumArea += (long)(x2 - x1) * (y2 - y1);}// 校验面积是否相等long totalArea = (long)(right - left) * (top - bottom);if (sumArea != totalArea) {return false;}// 步骤2:统计所有顶点的出现次数Map<Long, Integer> pointCount = new HashMap<>();for (int[] rect : rectangles) {int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];addPoint(pointCount, x1, y1);addPoint(pointCount, x1, y2);addPoint(pointCount, x2, y1);addPoint(pointCount, x2, y2);}// 步骤3:校验大矩形的四个顶点(必须出现1次,然后次数减为0)int[][] corners = {{left, bottom},{left, top},{right, bottom},{right, top}};for (int[] corner : corners) {int x = corner[0], y = corner[1];long key = getKey(x, y);Integer cnt = pointCount.get(key);if (cnt == null || cnt != 1) {return false;}pointCount.put(key, cnt - 1); // 次数减为0}// 步骤4:校验所有顶点的次数是否为偶数for (int count : pointCount.values()) {if (count % 2 != 0) {return false;}}return true;}private long getKey(int x, int y) {return (long)x << 32 | (y & 0xFFFFFFFFL);}private void addPoint(Map<Long, Integer> map, int x, int y) {long key = getKey(x, y);map.put(key, map.getOrDefault(key, 0) + 1);}
}

复杂度分析

  • 时间复杂度O(n)n 是小矩形数量。遍历矩形(O(n))、统计顶点(O(n),每个矩形4个顶点)、校验顶点(O(n),顶点数最多为 4n,但哈希表遍历是线性的)。
  • 空间复杂度O(n),哈希表最多存储 4n 个顶点(实际远小于,因为大量顶点会重复)。

示例验证

  • 示例1:面积相等,大矩形顶点各出现1次,其余顶点偶数次 → 返回 true
  • 示例2:存在间隙,面积虽相等,但顶点次数不满足 → 返回 false
  • 示例3:存在重叠,某顶点出现奇数次 → 返回 false

该方法通过面积和顶点的双重约束,高效判断完美覆盖,是处理几何覆盖问题的经典思路。

http://www.lryc.cn/news/599213.html

相关文章:

  • SQL164 2021年11月每天新用户的次日留存率
  • 虚拟地址-物理地址
  • 关于“PromptPilot”
  • jwt 验证方法 (ASP.NET Core)
  • Uniapp编写微信小程序,绘制动态圆环进度条
  • Linux——线程(下)
  • uniapp小程序上传图片并压缩
  • 【MacOS】发展历程
  • 基于 Nginx 与未来之窗防火墙构建下一代自建动态网络防护体系​—仙盟创梦IDE
  • 好看的小程序推广单页HTML源码 可用作导航页
  • 校园二手交易小程序的设计与实现
  • 如何将荣耀手机的照片传输到 Mac
  • 小程序安卓ApK转aab文件详情教程MacM4环境
  • Linux 时间同步的流程
  • 小程序卡顿到丝滑体验:ZKmall开源商城性能优化与兼容修复实战指南
  • 教培机构如何开发自己的证件照拍照采集小程序
  • 【pybind11】 pybind11如何调用python
  • 《整合Spring Cache:本地缓存、Redis与Caffeine对比实践》
  • Python 数据可视化之 Matplotlib 库
  • 【国内电子数据取证厂商龙信科技】谁是躲在“向日葵”后的
  • OSPF之多区域
  • 【ResNet50图像分类部署至RK3588】模型训练→转换RKNN→开发板部署
  • Jmeter的元件使用介绍:(四)前置处理器详解
  • JMeter每次压测前清除全部以确保异常率准确(以黑马点评为例、详细图解)
  • Pytorch中register_buffer和torch.nn.Parameter的异同
  • npm init vite-app runoob-vue3-test2 ,npm init vue@latest,指令区别
  • LIMA:大语言模型对齐的“少即是多”革命——原理、实验与范式重构
  • VR 技术在污水处理领域的创新性应用探索​
  • 华为云DRS实现Oracle到GaussDB数据库迁移的全流程技术方案
  • GTSuite许可与网络安全