我试图了解一个程序,任务是查找可能有多少个子数组,其总和等于给定值。
以下是从link提取的具有O(N)复杂度的工作代码:
static int findSubarraySum(int arr[], int K) {
Map<Integer, Integer> prevSum = new HashMap<>();
int res = 0;
int currsum = 0;
for (int i = 0; i < arr.length; i++) {
currsum += arr[i];
if (currsum == K)
res++;
if (prevSum.containsKey(currsum - K))
res += prevSum.get(currsum - K);
Integer count = prevSum.get(currsum);
if (count == null)
prevSum.put(currsum, 1);
else
prevSum.put(currsum, count + 1);
}
return res;
}
public static void main(String[] args) {
int arr[] = {10, 2, -2, -20, 10};
int sum = -10;
int n = arr.length;
System.out.println(findSubarraySum(arr, sum));
}
我无法理解下面代码的逻辑:
if (prevSum.containsKey(currsum - K))
res += prevSum.get(currsum - K);
以上代码中的HashMap如何有助于获得正确的结果。
答案 0 :(得分:1)
prevSum[i]
包含从第一个元素开始的,总计为i
的连续子数组的数量。例如,对于数组3, 4, 2, -4, 2
,条目将如下所示:
prevSum[3] = 1 // { { 3 } }
prevSum[5] = 1 // { { 3, 4, 2, -4 } }
prevSum[7] = 2 // { { 3, 4 }, { 3, 4, 2, -4, 2} }
prevSum[9] = 1 // { { 3, 4, 2 } }
如果当前前缀总和currsum
为10
,并且正在寻找总和为K=3
的子数组,则要删除以第一个元素开头并求和为7
以获取总计为3
的适当子数组。示例:
3, 4, 2, -4, 2, 1, 2, -5, 2
^
|------------------|
currsum = 10
|--| -> sums to 7
|-------------| -> sums to 3
|------------| -> sums to 7
|--| -> sums to 3
因此,在此位置,您找到了两个总计为K
的可能子数组。因此,res += prevSum.get(currsum - K)
。