题目:线性动态规划:连续数组(Contiguous Array)
字数 2273 2025-12-09 11:22:44

题目:线性动态规划:连续数组(Contiguous Array)


一、题目描述

给定一个二进制数组 nums(只包含 0 和 1),你需要找到其中含有相同数量的 0 和 1 的最长连续子数组的长度,并返回该长度。

示例 1:

输入:nums = [0,1]
输出:2
解释:[0, 1] 包含相同数量的 0 和 1,长度为 2。

示例 2:

输入:nums = [0,1,0]
输出:2
解释:[0, 1] 或 [1, 0] 都符合条件,最长长度为 2。

示例 3:

输入:nums = [0,0,1,0,1,1,0]
输出:6
解释:子数组 [0,0,1,0,1,1] 或 [0,1,0,1,1,0] 包含相同数量的 0 和 1,长度为 6。

二、问题分析

我们要求一个连续子数组,其中 0 和 1 的数量相等。
直接枚举所有子数组并统计其中 0 和 1 的个数,时间复杂度为 \(O(n^2)\),在数组较长时效率太低。
我们需要一种更聪明的方法,将问题转化为更易处理的形式。


三、关键思路转化

核心技巧:将 0 视为 -1,将 1 视为 +1。
这样,如果一个子数组中 0 和 1 的数量相等,那么该子数组的“和”就是 0。

举例
数组 [0, 1, 0, 0, 1, 1, 0] 转化为
[-1, +1, -1, -1, +1, +1, -1]

问题就转化为:寻找和为零的最长子数组


四、动态规划思路(实际上是前缀和 + 哈希表)

这个问题虽然归类为“线性动态规划”,但它更常见的解法是使用前缀和哈希表来在线性时间内解决。
我们定义一个变量 prefix_sum,表示从数组开头到当前位置的累加和(按上述 -1/+1 转换规则)。
我们希望找到两个位置 ijj > i),使得:

\[\text{prefix\_sum}[j] - \text{prefix\_sum}[i] = 0 \]

这意味着从 i+1j 的子数组和为 0,即 0 和 1 的数量相等。
所以,问题变成:寻找两个前缀和相等的最远距离


五、逐步解法

  1. 初始化

    • 用变量 current_sum 记录当前前缀和,初始为 0。
    • 用哈希表 map 记录每个前缀和第一次出现的位置(索引)。
    • (0, -1) 存入哈希表,表示前缀和为 0 出现在索引 -1(即数组开始之前)。
  2. 遍历数组

    • 对于每个元素 nums[i]
      • 如果 nums[i] == 0,则 current_sum -= 1
      • 如果 nums[i] == 1,则 current_sum += 1
    • 检查 current_sum 是否已经在哈希表中:
      • 如果存在,说明从之前第一次出现该前缀和的位置的下一个索引到当前位置,子数组和为 0。
        更新最大长度:max_len = max(max_len, i - map[current_sum])
      • 如果不存在,将 (current_sum, i) 存入哈希表。
  3. 遍历完成后max_len 即为所求。


六、举例推演

nums = [0, 1, 0, 0, 1, 1, 0] 为例:

索引 i nums[i] current_sum 哈希表记录(前缀和 → 第一次出现的索引) 最大长度更新
-1 - 0 {0: -1} -
0 0 -1 {0: -1, -1: 0} -
1 1 0 {0: -1, -1: 0} 1 - (-1) = 2
2 0 -1 {0: -1, -1: 0} 2 - 0 = 2
3 0 -2 {0: -1, -1: 0, -2: 3} -
4 1 -1 {0: -1, -1: 0, -2: 3} 4 - 0 = 4
5 1 0 {0: -1, -1: 0, -2: 3} 5 - (-1) = 6
6 0 -1 {0: -1, -1: 0, -2: 3} 6 - 0 = 6

最终最大长度为 6。


七、代码实现(Python)

def findMaxLength(nums):
    # 哈希表记录前缀和第一次出现的索引
    sum_to_index = {0: -1}
    current_sum = 0
    max_len = 0
    
    for i, num in enumerate(nums):
        # 将0视为-1,1视为+1
        current_sum += 1 if num == 1 else -1
        
        if current_sum in sum_to_index:
            # 如果之前出现过相同的前缀和,计算当前子数组长度
            max_len = max(max_len, i - sum_to_index[current_sum])
        else:
            # 第一次出现该前缀和,记录索引
            sum_to_index[current_sum] = i
    
    return max_len

八、复杂度分析

  • 时间复杂度\(O(n)\),只遍历数组一次。
  • 空间复杂度\(O(n)\),哈希表最多存储 \(n+1\) 个不同的前缀和。

九、总结

本题的核心是将“0 和 1 数量相等”转化为“子数组和为 0”,再通过前缀和与哈希表记录第一次出现的位置,从而在 \(O(n)\) 时间内找到最长满足条件的连续子数组。
这是一种典型的“前缀和+哈希表”技巧,在解决连续子数组相关问题时非常有用。

题目:线性动态规划:连续数组(Contiguous Array) 一、题目描述 给定一个二进制数组 nums (只包含 0 和 1),你需要找到其中含有相同数量的 0 和 1 的最长连续子数组的长度,并返回该长度。 示例 1: 示例 2: 示例 3: 二、问题分析 我们要求一个连续子数组,其中 0 和 1 的数量相等。 直接枚举所有子数组并统计其中 0 和 1 的个数,时间复杂度为 \(O(n^2)\),在数组较长时效率太低。 我们需要一种更聪明的方法,将问题转化为更易处理的形式。 三、关键思路转化 核心技巧 :将 0 视为 -1,将 1 视为 +1。 这样,如果一个子数组中 0 和 1 的数量相等,那么该子数组的“和”就是 0。 举例 : 数组 [0, 1, 0, 0, 1, 1, 0] 转化为 [-1, +1, -1, -1, +1, +1, -1] 。 问题就转化为: 寻找和为零的最长子数组 。 四、动态规划思路(实际上是前缀和 + 哈希表) 这个问题虽然归类为“线性动态规划”,但它更常见的解法是使用 前缀和 和 哈希表 来在线性时间内解决。 我们定义一个变量 prefix_sum ,表示从数组开头到当前位置的累加和(按上述 -1/+1 转换规则)。 我们希望找到两个位置 i 和 j ( j > i ),使得: \[ \text{prefix\_sum}[ j] - \text{prefix\_sum}[ i ] = 0 \] 这意味着从 i+1 到 j 的子数组和为 0,即 0 和 1 的数量相等。 所以,问题变成: 寻找两个前缀和相等的最远距离 。 五、逐步解法 初始化 : 用变量 current_sum 记录当前前缀和,初始为 0。 用哈希表 map 记录每个前缀和第一次出现的位置(索引)。 将 (0, -1) 存入哈希表,表示前缀和为 0 出现在索引 -1(即数组开始之前)。 遍历数组 : 对于每个元素 nums[i] : 如果 nums[i] == 0 ,则 current_sum -= 1 。 如果 nums[i] == 1 ,则 current_sum += 1 。 检查 current_sum 是否已经在哈希表中: 如果存在,说明从之前第一次出现该前缀和的位置的下一个索引到当前位置,子数组和为 0。 更新最大长度: max_len = max(max_len, i - map[current_sum]) 。 如果不存在,将 (current_sum, i) 存入哈希表。 遍历完成后 , max_len 即为所求。 六、举例推演 以 nums = [0, 1, 0, 0, 1, 1, 0] 为例: | 索引 i | nums[ i] | current_ sum | 哈希表记录(前缀和 → 第一次出现的索引) | 最大长度更新 | |--------|---------|-------------|----------------------------------------|--------------| | -1 | - | 0 | {0: -1} | - | | 0 | 0 | -1 | {0: -1, -1: 0} | - | | 1 | 1 | 0 | {0: -1, -1: 0} | 1 - (-1) = 2 | | 2 | 0 | -1 | {0: -1, -1: 0} | 2 - 0 = 2 | | 3 | 0 | -2 | {0: -1, -1: 0, -2: 3} | - | | 4 | 1 | -1 | {0: -1, -1: 0, -2: 3} | 4 - 0 = 4 | | 5 | 1 | 0 | {0: -1, -1: 0, -2: 3} | 5 - (-1) = 6 | | 6 | 0 | -1 | {0: -1, -1: 0, -2: 3} | 6 - 0 = 6 | 最终最大长度为 6。 七、代码实现(Python) 八、复杂度分析 时间复杂度 :\(O(n)\),只遍历数组一次。 空间复杂度 :\(O(n)\),哈希表最多存储 \(n+1\) 个不同的前缀和。 九、总结 本题的核心是将“0 和 1 数量相等”转化为“子数组和为 0”,再通过前缀和与哈希表记录第一次出现的位置,从而在 \(O(n)\) 时间内找到最长满足条件的连续子数组。 这是一种典型的“前缀和+哈希表”技巧,在解决连续子数组相关问题时非常有用。