You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

元素和等于长度的最长子数组:前缀和存储逻辑存疑

解析:寻找元素和等于自身长度的最长子数组的前缀和逻辑

问题回顾

我们需要找到数组中最长的子数组,满足子数组的元素和恰好等于它的长度。比如示例中输入[16, -1, 3, -7, 2, 8, 11, 24],符合条件的最长子数组是[-1, 3, -7, 2, 8],和为5,长度也为5。

核心数学推导

先明确几个定义:

  • prefixSum[k]:数组前k个元素的和(prefixSum[0] = 0,prefixSum[1] = arr[0],prefixSum[i+1] = arr[0]+arr[1]+...+arr[i])
  • 目标子数组范围[left, right](0-based):长度为right - left + 1,元素和为prefixSum[right+1] - prefixSum[left]

根据问题要求,元素和等于长度,列出等式:

prefixSum[right+1] - prefixSum[left] = right - left + 1

将等式整理变形,把含right+1的项移到左边,含left的项移到右边:

prefixSum[right+1] - (right+1) = prefixSum[left] - left

我们把prefixSum[k] - k定义为差值变量diff[k],等式简化为:

diff[right+1] = diff[left]

这意味着:如果遍历到right时,diff[right+1]的值在之前已经出现过(对应某个left),那么子数组[left, right]就满足元素和等于长度的条件,其长度为(right+1) - left。

对代码疑问的解析

你提到的currSum-(i+1)其实就是上面推导的diff[right+1](currSum等于prefixSum[i+1],i就是当前的right)。

你当前代码中的Line J存储的是currSum(即prefixSum[i+1]),这是错误的——正确的做法应该存储diff[i+1] = currSum-(i+1),这样才能通过查找相同的diff值找到符合条件的left,从而计算出正确的子数组长度。你的代码返回结果不符合示例(会得到长度4而非5),就是因为存储的是currSum而非diff值,导致计算的子数组范围错误。

修正后的核心代码

int longestSubarray(int n, vector<int> &arr) {
    unordered_map<long long,int> m;
    int maxLen = -1;
    long long currSum=0;
    
    // 初始化:prefixSum[0]-0 = 0-0=0,对应k=0(处理子数组从0开始的情况)
    m[0] = 0;
    
    for(int i=0; i<n; i++){
        currSum += arr[i];
        long long diff = currSum - (i+1);
        
        if(m.find(diff) != m.end()){
            // 找到对应的left,计算子数组长度
            int len = (i+1) - m[diff];
            maxLen = max(maxLen, len);
        } else {
            // 只存储首次出现的diff值,保证子数组最长
            m[diff] = i+1;
        }
    }
    return maxLen == -1 ? -1 : maxLen;
}

关键细节说明

为什么要存储首次出现的diff值?因为我们要找最长的子数组,对于同一个diff值,只需要记录它第一次出现的位置(最小的left),这样后续遇到相同diff时,计算出的子数组长度才是最大的。

内容的提问来源于stack exchange,提问作者Dae Hyun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 01:54:55