和为0的最长子数组

232 阅读2分钟

题目描述

给定一个数组 arr,其中包含正整数和负整数,任务是计算总和为 0 的最长子数组的长度

示例:

输入: arr[] = [15, -2, 2, -8, 1, 7, 10, 23]
输出: 5
解释: 总和为 0 的最长子数组是 [-2, 2, -8, 1, 7]

思路

前缀和+哈希的思路。

前缀和是什么?

对于一个数组nums,前缀和的定义为:

prefix[i] = nums[0] + nums[1] + nums[2] + ... + nums[i]。

举例,对于数组

[15, -2, 2, -8, 1, 7, 10, 23],其前缀和为 [15 ,13, 15, 7,8,15,10,33]。

通过计算前缀和,可以快速确定某段连续数组的和是否为0,比如坐标为0和坐标为2的前缀和差为:

prefix[2] - prefix[0] = 0

说明(0,2]区间上连续子数组的和为0。

[15, -2, 2, -8, 1, 7, 10, 23]

进一步,可以通过维护一个hash,hash的key为前缀和,hash的value为坐标。

算法步骤:

  • 遍历数组,如果前缀和为0,说明从开始到当前位置的连续子数组和为0。
  • 如果前缀和已经存在于哈希表中,则说明从哈希表记录的索引到当前位置的子数组和为 0。

实现

java

static  int maxLen(int arr[]) {
    // 创建哈希表存储前缀和及其对应的索引
    HashMap<Integer, Integer> prefixMap = new HashMap<>();
    int maxLength = 0;
    int prefixSum = 0;

    for (int i = 0; i < arr.length; i++) {
        prefixSum += arr[i]; // 计算前缀和

        // 如果前缀和为 0,则从开始到当前位置的子数组和为 0
        if (prefixSum == 0) {
            maxLength = i + 1;
        }

        // 如果前缀和已经存在于哈希表中
        if (prefixMap.containsKey(prefixSum)) {
            // 计算子数组长度并更新最大长度
            maxLength = Math.max(maxLength, i - prefixMap.get(prefixSum));
        } else {
            // 如果前缀和第一次出现,存储其索引
            prefixMap.put(prefixSum, i);
        }
    }

    return maxLength;
}

c++

class Solution {
public:
    int maxLen(vector<int>& arr) {
        unordered_map<int, int> hash;  // key 前缀和 value 前缀和的坐标
        int prefix = 0;
        int ans = 0;
        for (int i = 0;i < arr.size();i++) {
            prefix = prefix + arr[i];

            if (prefix == 0)
            {
                // 说明从数组的起始位置遍历到现在都是0
                ans = i + 1;
            }

            if (hash.find(prefix) != hash.end()) {
                ans = max(ans,i - hash[prefix]);
            }
            else
            {
                hash[prefix] = i;
            }
        }

        return ans;
    }
};

python3

class Solution:
    def maxLen(self, arr):
        prefix = 0
        ans = 0
        prefix_map = {}
        for index,val in enumerate(arr):
            prefix = prefix + val

            if prefix == 0:
                ans = index + 1

            if prefix in prefix_map:
                ans = max(ans,index- prefix_map[prefix])
            else:
                prefix_map[prefix] = index

        return ans

复杂度分析

时间复杂度为O(N),只需要遍历一遍数组。

空间复杂度O(N),需要维护一个哈希数组。