leetcode525:连续数组(前缀和解法)

#王者杯·14天创作挑战营·第4期#


LeetCode 525 (连续数组),【难度:中等;通过率:55.2%】,这道题的巧妙之处在于,它需要我们先对问题进行一次思维的转变,然后才能套用我们熟悉的算法模型

一、 题目描述

给定一个二进制数组 nums,找到含有相同数量的 01 的最长连续子数组,并返回该子数组的长度

示例:

输入: nums = [0,1]
输出: 2
解释: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组

输入: nums = [0,1,0]
输出: 2
解释: [0, 1] (或 [1, 0]) 是具有相同数量 0 和 1 的最长连续子数组

二、 核心思路 - “0”变“-1”

题目的要求是“相同数量的 0 和 1”。直接处理计数会比较复杂。这里有一个非常关键的思想转换:

如果我们将数组中所有的 0 都看作 -1,那么“0 和 1 数量相等”就等价于“子数组所有元素之和为 0”。

为什么呢?假设一个子数组中有 k1k0。经过转换后,这个子数组就变成了 k1k-1。它们的和自然就是 k * 1 + k * (-1) = 0

通过这个转换,问题就从“找到含有相同数量 0 和 1 的最长连续子数组”,变成了“找到和为 0 的最长连续子数组”。这是一个我们非常熟悉的前缀和问题!


三、 从“子数组和”到“前缀和”

现在问题是找到和为 0 的最长子数组。我们知道,一个从索引 ij 的子数组的和 sum(i, j) 可以通过前缀和数组 P 来计算:

sum(i, j) = P[j] - P[i-1]

我们希望 sum(i, j) == 0,这也就意味着 P[j] == P[i-1]

所以,问题再次被转换为:找到两个索引 i-1j,使得它们对应的前缀和相等,并求出所有这种情况中 j - (i-1) 的最大值。


四、 哈希表的妙用

为了高效地找到之前出现过的相同的前缀和,哈希表是我们的不二之选

  • Key: 前缀和的值
  • Value: 该前缀和第一次出现的索引

我们只需要记录第一次出现的索引,因为对于一个固定的终点 j,起点 i-1 的索引越小,子数组的长度 j - (i-1) 就越大

一个关键的初始化:我们需要在哈希表中预先放入 map.put(0, -1)。这有什么用呢?它用于处理那些从数组开头 index=0 开始的子数组。例如,如果 nums = [0, 1],转换后为 [-1, 1]

  • i=0 时,前缀和为 -1
  • i=1 时,前缀和为 -1 + 1 = 0。此时,我们在哈希表中查找 0,找到了它在索引 -1 处。子数组长度为 1 - (-1) = 2,这正是正确答案

五、 代码实现

这就是我们将上述所有思路融合在一起的最终代码

class Solution {
    public int findMaxLength(int[] nums) {
        // 1. 使用 HashMap 存储 <前缀和, 第一次出现的索引>
        HashMap<Integer, Integer> map = new HashMap<>();
      
        // 2. 关键初始化:处理从数组开头开始的子数组
        map.put(0, -1);
      
        int maxLength = 0;
        int currentSum = 0; // 动态计算的前缀和

        // 3. 一次遍历完成所有操作
        for (int i = 0; i < nums.length; i++) {
            // a. 将 0 视为 -1,动态更新前缀和
            currentSum += (nums[i] == 1 ? 1 : -1);

            // b. 检查当前前缀和是否已存在于 map 中
            if (map.containsKey(currentSum)) {
                // 如果存在,说明找到了一个和为 0 的子数组
                // 长度为 i - map.get(currentSum)
                maxLength = Math.max(maxLength, i - map.get(currentSum));
            } else {
                // c. 如果是第一次出现,记录其索引
                map.put(currentSum, i);
            }
        }

        return maxLength;
    }
}

执行用时情况

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


六、 关键点与复杂度分析

  • 思想转换:将“数量相等”问题转化为“和为 0”问题是解题的钥匙
  • 前缀和 + 哈希表:这是解决各类子数组和问题的标准、高效模式,必须熟练掌握
  • 边界处理map.put(0, -1) 的初始化是确保算法正确性的关键细节
  • 时间复杂度O(N) 我们只需要对数组进行一次遍历,哈希表的插入和查找操作平均时间复杂度为 O(1)
  • 空间复杂度O(N) 在最坏的情况下(例如,数组中全是 1),每个前缀和都不同,哈希表需要存储 N 个条目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值