和为k的最大子数组长度(前缀和)

和为k的最大子数组长度(前缀和)

问题重述:

给定一个数组arr,该数组无序,每一个元素均为正数,在给定一个正整数k,求arr的所有子数组中所有元素相加和为k的最长子数组的长度

例如:arr = [1,2,1,1,1],k=3,累加和为3的最长子数组为[1,1,1],所以返回结果3

问题分析:

求最长子数组和,我们可以想到使用前缀和,前缀和数组的两个下标之间的差值就是子数组长度

解法:

前缀和加哈希表优化

解题:

代码:
public static int subarraySum(int[] nums, int k) {
    int len = 0,sum = 0;
    // 定义一个哈希表,用于存储前缀和和前缀和出现位置
    Map<Integer,Integer> map = new HashMap<Integer,Integer>();
    // 从-1开始是为了记录第0个结点
    map.put(0,-1);
    for(int i = 0; i< nums.length;i++){
        sum += nums[i];
        if(map.containsKey(sum - k)){
            len = Math.max(i - map.get(sum - k),len);
        }
        if(!map.containsKey(sum)){
            map.put(sum,i);
        }
    }
    return len;
}

代码解析:

如果单纯的使用前缀和,不使用哈希表进行优化,那么就是对前缀和数组进行遍历,这道题因为全部是整数,所以我们遍历一遍就可以(全部是正数,当不符合要求,移动边界即可),如果数组中有负数的话,我们就需要使用两层for循环来对数组进行遍历(其中有负数,当不符合我们的条件的时候,我们需要遍历完右边的所有数据才能确定结果)。

使用前缀和加哈希表优化,不论其中有没有负数,都可以达到时间复杂度为O(n),我们遍历数组的时候,计算前缀和,我们将前缀和作为key,当前前缀和第一次出现的位置作为value存入哈希表中,当我们每一次遍历数组元素的时候,判断sum-k在哈希表中有没有对应的数据,如果有,从当前位置到哈希表中对应的位置之间的差值就是子数组的长度(通过sum-k可以得到子数组的长度是因为,我们计算k的时候是使用preSum[i]-preSum[j] = k,那么preSum[j] = preSum[i]-k,所以当哈希表中存在sum-k就表示当前前缀和数组中存在子数组和为k),遍历完数组后得到的最大长度就是最大子数组长度

总结:

前缀和方法一般用在求连续的累加和比如求连续子数组长度、二叉树的最大路径、,我们可以使用哈希表对前缀和进行优化

posted @ 2022-03-05 23:15  foldn  阅读(245)  评论(0)    收藏  举报