【前缀和】B003_LC_找两个和为目标值且不重叠的子数组(记录前缀和下标)

一、Problem

Given an array of integers arr and an integer target.

You have to find two non-overlapping sub-arrays of arr each with sum equal target. There can be multiple answers so you have to find an answer where the sum of the lengths of the two sub-arrays is minimum.

Return the minimum sum of the lengths of the two required sub-arrays, or return -1 if you cannot find such two sub-arrays.

Input: arr = [3,2,2,4,3], target = 3
Output: 2
Explanation: Only two sub-arrays have sum = 3 ([3] and [3]). The sum of their lengths is 2.

Constraints:

1 <= arr.length <= 10^5
1 <= arr[i] <= 1000
1 <= target <= 10^8

二、Solution

方法一:前缀和

  • 用 map 记录前缀和的每一项出现的位置 i i i
  • Q:如果找和为 tar 的子数组呢?
    A:如果 pre[i] - tar 在 map 的 keySet 中出现过,如果出现位置为 l l l,且当前位置为 r r r,则表明数组中存在一段长为 r − l r-l rl 的且和为 tar 的子数组。
  • Q:如何判断两个和为 tar 的子数组是否重叠?
    A:第二长的子数组的左端点大于大于第一小的子数组的右端点。证明:第一短的子数组一定是第一个找到,第二长的子数组一定是第二个找到。
class Solution {
    public int minSumOfLengths(int[] a, int tar) {
        int n = a.length, INF = 0x3f3f3f3f, pre[] = new int[n+1];
        Map<Integer, Integer> mp = new HashMap<>();
        mp.put(0, 0);
        for (int i = 1; i <= n; i++) {
            pre[i] = pre[i-1] + a[i-1];
            mp.put(pre[i], i);
        }
        int fir = INF, sec = INF, minR = 0;
        
        for (int r = 1; r <= n; r++) {
            int d = pre[r] - tar;
            if (mp.containsKey(d)) {
                int l = mp.get(d), len = Math.abs(r - l);
                if (len < fir) {
                    minR = r;
                    sec = fir;
                    fir = len;
                } else if (len < sec && l >= minR)
                    sec = len;
            }
        }
        return fir != INF && sec != INF ? fir+sec : -1;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

你可能感兴趣的:(#,前缀和与差分)