题目描述

✅ LCR 011. 连续数组

image-20260928234801722

题意分析

数组只含零和一,求其中零与一数量相同的最长连续子数组长度。要求连续,不能挑选不相邻元素;找不到这样的非空区间时返回零。

合法区间的两类数量相同,因此长度一定为偶数,但只检查长度为偶数并不够,还需要准确判断两类数量是否平衡。

解法:前缀平衡值与最早位置

核心思路

[!blue]

将一视为 +1,零视为 -1,区间累计值就等于一的个数减去零的个数。两类数量相同,恰好等价于这个区间和为零;只需在扫描时这样计分,不必真的修改输入数组。

用 s 保存已扫描前缀的平衡值。若结束于下标 j 和结束于当前下标 i 的两个前缀值相同,那么它们之间的区间 nums[j+1..i] 平衡值为零,长度为 i - j。

对固定的当前右端,同值历史前缀越早出现,得到的区间就越长。因此哈希表 d 只保存每个平衡值第一次出现的位置。再次遇到相同值时,用它计算长度即可,不覆盖原位置;后来的同值位置对于任何未来右端都不可能更优。

初始化 d[0] = -1,表示第一个元素之前的空前缀。如果当前整个前缀平衡,长度就统一算成 i - (-1),自然覆盖从下标零开始的答案。

每个右端都与相同平衡值的最早位置配对,得到这个右端下最长的合法候选,再取全局最大值。映射中有正负贡献,普通窗口不能依据和的大小单调收缩,而前缀相等关系不受这个影响。

解题步骤

  1. 初始化平衡值和答案为零,记录空前缀 d[0] = -1。
  2. 从左到右扫描,一使平衡值加一,零使平衡值减一。
  3. 若当前平衡值已有记录,用当前下标减去最早下标更新最大长度。
  4. 若未出现过,记录当前下标作为它的首次位置。
  5. 扫描结束后返回答案,未命中时自然保持零。

代码实现

class Solution {
    public int findMaxLength(int[] nums) {
        Map<Integer, Integer> d = new HashMap<>();

        // 空前缀:和为 0,虚拟下标 -1,使「从头开始」的区间长度算作 i - (-1)。
        d.put(0, -1);
        int answer = 0;
        int s = 0;

        for (int i = 0; i < nums.length; ++i) {
            // 0 记 -1、1 记 +1,「数量相同」就变成「区间和为 0」。
            s += nums[i] == 0 ? -1 : 1;

            if (d.containsKey(s)) {
                answer = Math.max(answer, i - d.get(s));
            } else {
                // 只记最早出现的位置,越靠左区间越长。
                d.put(s, i);
            }
        }

        return answer;
    }
}
func findMaxLength(nums []int) (answer int) {
    d := map[int]int{0: -1}
    s := 0
    for i, x := range nums {
        if x == 1 {
            s++
        } else {
            s--
        }
        if j, ok := d[s]; ok {
            answer = max(answer, i-j)
        } else {
            d[s] = i
        }
    }
    return
}

复杂度分析

设数组长度为 $n$。

  • 时间复杂度:期望 $O(n)$,每个位置进行常数次哈希操作。
  • 辅助空间复杂度:$O(n)$,至多记录 $n+1$ 种平衡值的首次位置。

关键点总结

[!green]

  • 零记负一、一记正一,把数量平衡转换为区间和为零。
  • 相等前缀之间的区间合法,求最长就始终保留最早位置。
  • 空前缀在虚拟下标负一,长度统一为两个前缀下标之差。

易错点总结

[!yellow]

  • 仍把零当成数值零累加,得到的只是一个数的数量,不能表示两类平衡。
  • 空前缀位置写成零,会使从数组开头开始的区间少算一个元素。
  • 长度已经是 i - d[s],不要再加一,因为记录的是左端之前的位置。
  • 覆盖为较晚的相同平衡值位置,会缩短后续候选,漏掉最长答案。
  • 本题保存最早位置而不是频次;频次只能回答数量,不能直接给出最远距离。

相似题目

题目 难度 关联与区别
560. 和为 K 的子数组 中等 把0改成-1后,0与1等量等价于区间和为0;本题保存最早前缀位置求最长长度,而非统计数量。
1124. 表现良好的最长时间段 中等 同样把两类元素映射成正负贡献,原题要求区间和严格为正,本题要求等于0。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/83305033
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!