leetcode
leetcode 2551 ~ 2600
移除栅栏得到的正方形田地的最大面积

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

难度:

标签:

题目描述

There is a large (m - 1) x (n - 1) rectangular field with corners at (1, 1) and (m, n) containing some horizontal and vertical fences given in arrays hFences and vFences respectively.

Horizontal fences are from the coordinates (hFences[i], 1) to (hFences[i], n) and vertical fences are from the coordinates (1, vFences[i]) to (m, vFences[i]).

Return the maximum area of a square field that can be formed by removing some fences (possibly none) or -1 if it is impossible to make a square field.

Since the answer may be large, return it modulo 109 + 7.

Note: The field is surrounded by two horizontal fences from the coordinates (1, 1) to (1, n) and (m, 1) to (m, n) and two vertical fences from the coordinates (1, 1) to (m, 1) and (1, n) to (m, n). These fences cannot be removed.

 

Example 1:

Input: m = 4, n = 3, hFences = [2,3], vFences = [2]
Output: 4
Explanation: Removing the horizontal fence at 2 and the vertical fence at 2 will give a square field of area 4.

Example 2:

Input: m = 6, n = 7, hFences = [2], vFences = [4]
Output: -1
Explanation: It can be proved that there is no way to create a square field by removing fences.

 

Constraints:

  • 3 <= m, n <= 109
  • 1 <= hFences.length, vFences.length <= 600
  • 1 < hFences[i] < m
  • 1 < vFences[i] < n
  • hFences and vFences are unique.

代码结果

运行时间: 644 ms, 内存: 36.2 MB


// 思路:
// 1. 使用Java Stream对水平和垂直栅栏排序,并找到每一块区域的最大边长。
// 2. 通过计算最大正方形边长来判断结果。
// 3. 返回最大正方形的面积,如果没有则返回-1。
// 注意:取余 10^9 + 7

import java.util.*;
import java.util.stream.*;

public class Solution {
    public int maxSquareArea(int m, int n, int[] hFences, int[] vFences) {
        Arrays.sort(hFences);
        Arrays.sort(vFences);

        int maxHGap = Math.max(hFences[0] - 1, m - hFences[hFences.length - 1]);
        int maxVGap = Math.max(vFences[0] - 1, n - vFences[vFences.length - 1]);

        maxHGap = IntStream.range(1, hFences.length)
                .map(i -> hFences[i] - hFences[i - 1] - 1)
                .reduce(maxHGap, Math::max);

        maxVGap = IntStream.range(1, vFences.length)
                .map(i -> vFences[i] - vFences[i - 1] - 1)
                .reduce(maxVGap, Math::max);

        int maxSide = Math.min(maxHGap, maxVGap);
        if (maxSide == 0) return -1;

        long area = (long) maxSide * maxSide % (1000000007);
        return (int) area;
    }
}

解释

方法:

此题解的思路是首先对水平栅栏和垂直栅栏的坐标进行排序,并在两个数组的开始和结尾分别添加边界栅栏的坐标。然后,通过双重循环遍历所有可能的正方形的大小,对于每个大小,检查是否存在对应的水平栅栏和垂直栅栏组合来形成一个正方形。这是通过在一个集合中存储所有垂直栅栏间距的唯一值,并在遍历水平栅栏时检查该集合中是否存在与当前水平栅栏间距相等的值来实现的。如果找到这样的组合,则更新最大正方形的边长。最后,返回最大正方形的面积。

时间复杂度:

O(h log h + v log v + v^2 + h^2)

空间复杂度:

O(h + v + v^2)

代码细节讲解

🦆
为什么题解中选用集合存储垂直栅栏的间距,而不是使用其他数据结构如列表或字典?
集合(Set)被用来存储垂直栅栏的间距,因为集合具有唯一性和快速查找的特性。使用集合可以自动去除重复的间距值,并且在后续判断是否存在某个特定的间距时,集合能够提供平均常数时间复杂度的查找效率(O(1)时间复杂度)。若使用列表,查找一个元素的平均时间复杂度是O(n),如果使用字典虽然也可以实现类似集合的效率,但其存储和管理键值对的额外结构在这里并不必要,因为我们只关心间距值的存在性,而不是它们的频率或其他属性。
🦆
在检查水平栅栏时,为什么需要同时从最大间距开始向内逐步减小间距进行检查?
在检查水平栅栏时从最大间距开始向内逐步减小间距进行检查的原因是,我们目标是找到最大的可能正方形边长。从最大可能间距开始并逐渐减小可以尽快地找到最大的合法边长。一旦发现一个合法的边长,由于边长是递减检查的,可以保证这是当前遍历过的最大合法边长,从而可以及时终止进一步的无效检查,提高算法的效率。
🦆
题解中提到的`如果找到这样的组合,则更新最大正方形的边长`,具体是如何确定找到一个有效的正方形的?
在题解中,一个有效的正方形是通过检查水平栅栏和垂直栅栏的间距是否相等来确认的。具体地,对于每一个考虑的水平栅栏间距,代码检查是否存在一个相同长度的垂直栅栏间距。如果这样的垂直间距存在于之前存储的集合中,那么说明可以构成一个边长为该间距的正方形。这时,如果这个边长比当前记录的最大边长还要大,就会更新最大边长的记录。
🦆
在计算最大正方形面积时,为什么要取结果对`109 + 7`取余?这个数字有什么特别的意义吗?
在计算结果时对`109 + 7`取余是常见的做法,尤其是在编程竞赛或算法实现中,主要是为了防止计算结果过大导致的整数溢出,并可以保持结果的稳定性。`1000000007`(10^9 + 7)是一个大质数,质数的使用在模运算中有良好的数学性质,可以减少潜在的哈希冲突,同时也是为了符合一些编程比赛的标准输出要求。

相关问题