【LeetCode 每日一题】2975. 移除栅栏得到的正方形田地的最大面积

Problem: 2975. 移除栅栏得到的正方形田地的最大面积

文章目录

  • 整体思路
      • [1. 核心问题](#1. 核心问题)
      • [2. 算法逻辑](#2. 算法逻辑)
  • 完整代码
  • 时空复杂度
      • [1. 时间复杂度: O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2)](#1. 时间复杂度: O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2))
      • [2. 空间复杂度: O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2)](#2. 空间复杂度: O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2))

整体思路

1. 核心问题

我们需要在一个 m × n m \times n m×n 的矩形田地中,选择水平栅栏(hFences)和垂直栅栏(vFences),构建一个正方形区域。

  • 田地的边界分别是水平线 1m,垂直线 1n
  • 输入给定的 hFencesvFences 是中间的栅栏,边界栅栏默认存在。
  • 目标:找到可能形成的正方形的最大面积。如果无法形成,返回 -1。

2. 算法逻辑

正方形的边长取决于两个栅栏之间的间距

  • 如果在水平方向上存在两个栅栏,它们之间的距离为 L L L。
  • 如果在垂直方向上也存在两个栅栏,它们之间的距离也为 L L L。
  • 那么这两个间距组合起来就能围成一个边长为 L L L 的正方形。

步骤

  1. 预处理栅栏 :对于水平和垂直方向,都要把边界1mn)加入到给定的栅栏数组中。
  2. 计算所有可能的间距
    • 分别计算水平方向所有可能的间距集合 hSet
    • 分别计算垂直方向所有可能的间距集合 vSet
    • 这里使用双重循环遍历排序后的栅栏数组,计算任意两根栅栏之间的距离 fences[j] - fences[i]
  3. 寻找交集最大值
    • 遍历其中一个集合(如 hSet),检查其中的间距是否也存在于另一个集合 vSet 中。
    • 如果是,说明这个长度 L L L 既可以是宽也可以是高,能构成正方形。更新最大边长 ans
  4. 计算结果 :如果找到了合法的正方形(ans > 0),返回面积并取模;否则返回 -1。

完整代码

java 复制代码
import java.util.*;

class Solution {
    final int MOD = 1_000_000_007;

    public int maximizeSquareArea(int m, int n, int[] hFences, int[] vFences) {
        // 1. 获取水平方向所有可能的间距集合
        // m 是水平方向的边界坐标 (行数)
        Set<Integer> hSet = gapSet(hFences, m);
        
        // 2. 获取垂直方向所有可能的间距集合
        // n 是垂直方向的边界坐标 (列数)
        Set<Integer> vSet = gapSet(vFences, n);
        
        // 记录最大合法边长
        int ans = 0;
        
        // 3. 寻找两个集合的交集中的最大值
        // 遍历水平间距集合
        for (int x : hSet) {
            // 如果垂直方向也有相同的间距 x
            if (vSet.contains(x)) {
                // 更新最大边长
                ans = Math.max(ans, x);
            }
        }
        
        // 4. 计算面积并返回
        if (ans == 0) {
            return -1; // 没有找到任何匹配的间距(实际上通常至少有 min(m-1, n-1),除非输入限制特殊)
        }
        
        // 面积可能很大,需要转换成 long 进行乘法,然后取模
        return (int)((long) ans * ans % MOD);
    }

    // 辅助方法:计算所有可能的栅栏间距
    // fences: 内部栅栏坐标数组
    // boundary: 边界坐标 (对应 m 或 n)
    private Set<Integer> gapSet(int[] fences, int boundary) {
        int len = fences.length;
        
        // 创建新数组,长度比原数组多 2,用于存放边界 1 和 boundary
        // fences 本身是引用传递,为了不修改原数组并加入新元素,使用 copyOf
        fences = Arrays.copyOf(fences, len + 2);
        
        // 添加边界栅栏
        fences[len] = 1;
        fences[len + 1] = boundary;
        
        // 排序,方便从小到大计算间距
        Arrays.sort(fences);
        
        // 使用 HashSet 存储所有可能的间距,自动去重
        Set<Integer> st = new HashSet<>();
        
        // 双重循环枚举任意两根栅栏
        for (int i = 0; i < fences.length; i++) {
            for (int j = i + 1; j < fences.length; j++) {
                // 计算间距并加入集合
                st.add(fences[j] - fences[i]);
            }
        }
        return st;
    }
}

时空复杂度

假设 hFences 长度为 H H H,vFences 长度为 V V V。

1. 时间复杂度: O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2)

  • gapSet 函数
    • 排序: O ( H log ⁡ H ) O(H \log H) O(HlogH)。
    • 双重循环枚举所有间距:这是一个组合问题,次数为 C ( H , 2 ) ≈ O ( H 2 ) C(H, 2) \approx O(H^2) C(H,2)≈O(H2)。
    • HashSet 插入操作平均 O ( 1 ) O(1) O(1)。
    • 因此,处理水平栅栏耗时 O ( H 2 ) O(H^2) O(H2),处理垂直栅栏耗时 O ( V 2 ) O(V^2) O(V2)。
  • 交集查找
    • 遍历 hSet,其大小最多为 O ( H 2 ) O(H^2) O(H2)。
    • vSet 中查找,平均 O ( 1 ) O(1) O(1)。
    • 这部分耗时 O ( H 2 ) O(H^2) O(H2)。
  • 总计 : O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2)。
    • 注意:如果 H H H 或 V V V 很大(例如 10 5 10^5 105),这个 O ( N 2 ) O(N^2) O(N2) 算法会超时。但根据题目(LeetCode 2975)的数据约束,栅栏数量通常较小(如 600),允许 O ( N 2 ) O(N^2) O(N2) 通过。

2. 空间复杂度: O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2)

  • 计算依据
    • 我们需要两个 HashSet 来存储所有可能的间距。
    • 水平方向最多有 ( H + 2 ) ( H + 1 ) 2 \frac{(H+2)(H+1)}{2} 2(H+2)(H+1) 个间距,即 O ( H 2 ) O(H^2) O(H2)。
    • 垂直方向最多有 O ( V 2 ) O(V^2) O(V2) 个间距。
  • 结论 : O ( H 2 + V 2 ) O(H^2 + V^2) O(H2+V2)。

参考灵神

相关推荐
少许极端2 小时前
算法奇妙屋(二十五)-递归问题
算法·递归·汉诺塔
Remember_9932 小时前
【数据结构】初识 Java 集合框架:概念、价值与底层原理
java·c语言·开发语言·数据结构·c++·算法·游戏
:mnong2 小时前
通过交互式的LLM算法可视化工具学习大语言模型原理
学习·算法·语言模型
Remember_9932 小时前
【数据结构】Java集合核心:线性表、List接口、ArrayList与LinkedList深度解析
java·开发语言·数据结构·算法·leetcode·list
甄心爱学习2 小时前
leetcode打卡
算法·leetcode·职场和发展
dragoooon342 小时前
[hot100 NO.62~67]
算法
进击的横打2 小时前
结构化思维之PERP原则
职场和发展
你撅嘴真丑2 小时前
求矩阵的两对角线上的元素之和 与 sizeof的大作用
线性代数·算法·矩阵
程序员三明治2 小时前
【面试手撕】如何构造二叉树输入用例?ACM模式,路径总和2解题思路
算法·leetcode·面试·acm·构造二叉树·路径总和