【LeetCode 每日一题】2943. 最大化网格图中正方形空洞的面积——(解法二)哈希集合

Problem: 2943. 最大化网格图中正方形空洞的面积

文章目录

  • 整体思路
      • [1. 核心逻辑](#1. 核心逻辑)
      • [2. 算法改进: O ( N ) O(N) O(N) 查找最长连续序列](#2. 算法改进: O ( N ) O(N) O(N) 查找最长连续序列)
  • 完整代码
  • 时空复杂度
      • [1. 时间复杂度: O ( H + V ) O(H + V) O(H+V)](#1. 时间复杂度: O ( H + V ) O(H + V) O(H+V))
      • [2. 空间复杂度: O ( H + V ) O(H + V) O(H+V)](#2. 空间复杂度: O ( H + V ) O(H + V) O(H+V))

整体思路

1. 核心逻辑

这段代码解决的问题与上一段完全相同,依然是通过计算水平和垂直方向移除栏杆后形成的最大连续空隙来确定最大正方形边长。

公式不变: S i d e = min ⁡ ( MaxH , MaxV ) + 1 Side = \min(\text{MaxH}, \text{MaxV}) + 1 Side=min(MaxH,MaxV)+1。

2. 算法改进: O ( N ) O(N) O(N) 查找最长连续序列

之前的实现使用了排序 ( O ( N log ⁡ N ) O(N \log N) O(NlogN)),这里改用 哈希集合 (HashSet) 来实现 O ( N ) O(N) O(N) 的查找。这与解决 LeetCode 128 (Longest Consecutive Sequence) 的经典算法一致。

  • 逻辑步骤
    1. 去重与快速查找 :将所有栏杆编号放入 HashSet 中。这一步同时也完成了去重(虽然题目通常保证栏杆不重复)。
    2. 寻找序列起点 :遍历集合中的每个元素 x
      • 检查 x - 1 是否存在。
      • 如果 x - 1 存在,说明 x 并不是一个连续序列的起点 。我们跳过它,因为包含 x 的那个序列肯定已经从更小的数字(比如 x-1 或更小)开始计算过了。
      • 如果 x - 1 不存在,说明 x 是一个新的连续序列的开头
    3. 延伸序列 :从起点 x 开始,不断检查 x+1, x+2... 是否在集合中,直到断裂。
    4. 更新最大值 :计算该序列长度,更新全局最大值 ans

完整代码

java 复制代码
import java.util.HashSet;
import java.util.Set;

class Solution {
    public int maximizeSquareHoleArea(int n, int m, int[] hBars, int[] vBars) {
        // 逻辑与之前相同:
        // 1. 计算水平和垂直方向上移除栏杆形成的最长连续区间
        // 2. 边长取两者最小值 + 1(因为移除 k 个栏杆得到 k+1 的长度)
        int l = Math.min(maxConsecutive(hBars), maxConsecutive(vBars)) + 1;
        
        // 返回面积
        return l * l;
    }

    // 辅助函数:使用 HashSet 计算数组中最长连续序列的长度
    // 复杂度优化为 O(N)
    private int maxConsecutive(int[] nums) {
        // 1. 将所有元素放入 HashSet,实现 O(1) 查找
        Set<Integer> st = new HashSet<>();
        for (int num : nums) {
            st.add(num);
        }

        int ans = 1; // 初始化为 1,只要数组非空,至少有长度 1
        // 如果题目允许输入空数组,这里应处理 ans = 0 的情况。
        // 但本题约束通常保证至少有一个栏杆。
        
        // 2. 遍历集合中的每个元素
        for (int x : st) {
            // 核心剪枝逻辑:
            // 如果集合中包含 x-1,说明 x 肯定不是连续序列的起点。
            // 我们只在遇到序列起点时才开始计数,避免重复计算。
            // 例如序列 [2, 3, 4],遍历到 3 和 4 时都会跳过,只有遍历到 2 时才进入 while。
            if (st.contains(x - 1)) {
                continue;
            }
            
            // 3. 从起点开始向后延伸查找
            int y = x + 1;
            while (st.contains(y)) {
                y++;
            }
            
            // 4. 更新最大长度
            // 序列是 [x, x+1, ..., y-1],长度为 (y-1) - x + 1 = y - x
            ans = Math.max(ans, y - x);
        }
        return ans;
    }
}

时空复杂度

假设 hBars 的长度为 H H H,vBars 的长度为 V V V。

1. 时间复杂度: O ( H + V ) O(H + V) O(H+V)

  • 计算依据
    • maxConsecutive 函数中:
      • 将数组转入 HashSet:遍历一次数组,耗时 O ( N ) O(N) O(N)。
      • 遍历 HashSet:虽然外层有个 for 循环,内层有个 while 循环,看起来像 O ( N 2 ) O(N^2) O(N2),但实际上每个数字最多被访问两次
        • 第一次:在外层 for 循环中作为 x 被访问。
        • 第二次:在内层 while 循环中作为 y 被访问(仅当它是某个序列的一部分时)。
        • 由于 if (st.contains(x - 1)) 的存在,每个连续序列只会被其头部元素触发一次 while 循环。
    • 因此,maxConsecutive(hBars) 耗时 O ( H ) O(H) O(H),maxConsecutive(vBars) 耗时 O ( V ) O(V) O(V)。
  • 结论 : O ( H + V ) O(H + V) O(H+V)。相比排序解法 O ( N log ⁡ N ) O(N \log N) O(NlogN),这在理论上更优。

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

  • 计算依据
    • 我们需要两个 HashSet 来存储 hBarsvBars 中的所有元素。
    • 空间消耗与输入数组的长度成线性关系。
  • 结论 : O ( H + V ) O(H + V) O(H+V)。
    • 对比 :排序解法的空间复杂度为 O ( log ⁡ N ) O(\log N) O(logN)(栈空间),这里牺牲了空间换取了时间。
相关推荐
念何架构之路1 小时前
Go语言加密算法
数据结构·算法·哈希算法
AI科技星1 小时前
《数学公理体系·第三部·数术几何》(2026 年版)
c语言·开发语言·线性代数·算法·矩阵·量子计算·agi
失去的青春---夕阳下的奔跑1 小时前
560. 和为 K 的子数组
数据结构·算法·leetcode
黎阳之光1 小时前
黎阳之光:以视频孪生重构智慧医院信息化,打造高标项目核心竞争力
大数据·人工智能·物联网·算法·数字孪生
丷丩2 小时前
三级缓存下MVT地图瓦片服务性能优化策略
算法·缓存·性能优化·gis·geoai-up
m0_629494732 小时前
LeetCode 热题 100-----25.回文链表
数据结构·算法·leetcode·链表
ʚ希希ɞ ྀ3 小时前
单词拆分----dp
算法
智者知已应修善业4 小时前
【51单片机LED闪烁10次数码管显示0-9】2023-12-14
c++·经验分享·笔记·算法·51单片机
智者知已应修善业4 小时前
【51单片机2按键控制1个敞亮LED灯闪烁和熄灭】2023-11-3
c++·经验分享·笔记·算法·51单片机
AI算法沐枫4 小时前
大模型 | 大模型之机器学习基本理论
人工智能·python·神经网络·学习·算法·机器学习·计算机视觉