leetcode
leetcode 2501 ~ 2550
最大化网格图中正方形空洞的面积

最大化网格图中正方形空洞的面积

难度:

标签:

题目描述

You are given the two integers, n and m and two integer arrays, hBars and vBars. The grid has n + 2 horizontal and m + 2 vertical bars, creating 1 x 1 unit cells. The bars are indexed starting from 1.

You can remove some of the bars in hBars from horizontal bars and some of the bars in vBars from vertical bars. Note that other bars are fixed and cannot be removed.

Return an integer denoting the maximum area of a square-shaped hole in the grid, after removing some bars (possibly none).

 

Example 1:

Input: n = 2, m = 1, hBars = [2,3], vBars = [2]

Output: 4

Explanation:

The left image shows the initial grid formed by the bars. The horizontal bars are [1,2,3,4], and the vertical bars are [1,2,3].

One way to get the maximum square-shaped hole is by removing horizontal bar 2 and vertical bar 2.

Example 2:

Input: n = 1, m = 1, hBars = [2], vBars = [2]

Output: 4

Explanation:

To get the maximum square-shaped hole, we remove horizontal bar 2 and vertical bar 2.

Example 3:

Input: n = 2, m = 3, hBars = [2,3], vBars = [2,4]

Output: 4

Explanation:

One way to get the maximum square-shaped hole is by removing horizontal bar 3, and vertical bar 4.

 

Constraints:

  • 1 <= n <= 109
  • 1 <= m <= 109
  • 1 <= hBars.length <= 100
  • 2 <= hBars[i] <= n + 1
  • 1 <= vBars.length <= 100
  • 2 <= vBars[i] <= m + 1
  • All values in hBars are distinct.
  • All values in vBars are distinct.

代码结果

运行时间: 24 ms, 内存: 16.7 MB


/*
 * 思路:
 * 1. 找出横线段和竖线段中连续的最大间隔。
 * 2. 横线段和竖线段的最大间隔决定了最大正方形的边长。
 * 3. 最大正方形的面积即为最大间隔的平方。
 */
import java.util.Arrays;
import java.util.stream.IntStream;

public class MaxSquareAreaStream {
    public static int maxSquareArea(int n, int m, int[] hBars, int[] vBars) {
        Arrays.sort(hBars);
        Arrays.sort(vBars);

        int maxHGap = IntStream.range(0, hBars.length - 1)
                .map(i -> hBars[i + 1] - hBars[i] - 1)
                .reduce(Math.max(hBars[0] - 1, n + 2 - hBars[hBars.length - 1]), Math::max);

        int maxVGap = IntStream.range(0, vBars.length - 1)
                .map(i -> vBars[i + 1] - vBars[i] - 1)
                .reduce(Math.max(vBars[0] - 1, m + 2 - vBars[vBars.length - 1]), Math::max);

        int maxSquareSide = Math.min(maxHGap, maxVGap);
        return maxSquareSide * maxSquareSide;
    }

    public static void main(String[] args) {
        int n = 2, m = 1;
        int[] hBars = {2, 3};
        int[] vBars = {2};
        System.out.println(maxSquareArea(n, m, hBars, vBars)); // 输出 4
    }
}

解释

方法:

为了找到最大的正方形空洞,首先我们需要确定在横向和纵向上可以形成的最大连续空洞的长度。这是因为正方形的大小由其最短的边决定。\n\n函数 `f(a)` 的作用是接收一个整数列表,这些整数代表可以移除的线段的编号。首先,将这些编号进行排序,然后遍历排序后的数组,寻找最长的连续序列,这个序列的长度即为在该方向上可以形成的最大空间的边长。\n\n遍历时,使用 `st` 记录当前连续序列的起始位置,`i` 用于探索序列的结束位置。如果当前位置和前一个位置的差值为1,则继续向前探索;否则,比较当前连续序列的长度和已知的最大长度,更新最大长度,并重置 `st`。\n\n最后,将最长连续序列的长度加1(因为长度n的序列对应的是n+1个连续的网格),然后在横向和纵向上找到的最长长度中取最小值,因为正方形的边长由短边决定。最后将这个长度的平方作为结果返回,因为面积是边长的平方。

时间复杂度:

O(h log h + v log v)

空间复杂度:

O(k)

代码细节讲解

🦆
为什么在计算最大连续空洞时,需要将线段编号进行排序?
在计算最大连续空洞时,需要将线段编号进行排序以确保能正确地计数连续的线段。如果不排序,线段编号可能是无序的,这样在遍历时无法直接通过比较相邻元素来判断是否连续。排序后,连续的线段编号将会相邻出现,这使得程序可以通过简单的递增遍历来找出最长的连续区间,从而确定最大的空洞边长。
🦆
在函数`f(a)`中,如果输入的线段编号已经是连续的,如何处理这种特殊情况?
如果输入的线段编号已经是连续的,函数`f(a)`的处理方式不变。首先,函数会检查列表是否已经排序,然后从列表的开始遍历,计算最长的连续区间。在这种情况下,整个列表本身就是一个连续区间,所以函数会在一次遍历中找到这个连续区间并计算其长度。最终返回的长度还需要加1,以反映连续线段所覆盖的网格数量。
🦆
这种方法在处理线段编号时,为什么差值必须为1才认为是连续?如果差值大于1如何处理?
在处理线段编号时,差值必须为1才认为是连续,是因为连续的线段编号表示这些线段在网格图中相邻。如果两个线段编号的差值为1,说明它们在网格中是挨着的,没有间断。如果差值大于1,这表示在两个编号之间至少有一个网格没有被覆盖,这导致连续性中断。在这种情况下,我们需要结束当前连续序列的计数,并在遇到下一个连续序列时重新开始计数。
🦆
函数`f(a)`返回的是连续序列的长度加1,这种处理方式背后的逻辑是什么?
函数`f(a)`返回连续序列的长度加1的处理方式背后的逻辑是,连续序列的长度实际上表示的是相邻线段之间的‘空档数’。例如,如果有一个连续序列的线段编号为[2, 3, 4],那么这表示有三根线段,但实际上它们覆盖了四个网格(从网格2到网格5)。因此,我们需要在连续序列的长度基础上加1,以正确表示被这些连续线段覆盖的网格总数。

相关问题