题意
给定长度为n的整数数组,统计和等于x的连续子数组数量。
超时写法:暴力枚举(双重循环)
思路
枚举每个子数组的起点 (i),再从 (i) 向右枚举终点 (j),维护从 (i) 到 (j) 的累加和 sum:
- 每次
sum += arr[j] - 若
sum == x,则答案ans++
这样能统计所有连续子数组,但当 (n) 很大时会超时。
复杂度
- 时间复杂度: O ( n 2 ) O(n^{2}) O(n2)
代码
cpp
#include<bits/stdc++.h>
using namespace std;
int n, x, s = 0, e = 0, ans = 0;
int arr[100005];
int main() {
cin >> n >> x;
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += arr[j];
if (sum == x) ans++;
}
}
cout << ans;
return 0;
}//by wqs
前缀和 + Hash 优化
思路
用前缀和思想:设当前前缀和为 sum,如果存在某个以前出现过的前缀和为 sum - x,那么从那个位置之后到当前位置的子数组和就是 (x)。
做法是用 unordered_map 统计每个前缀和出现次数:
- 初始化
prefix_sum_unordered_map[0] = 1(表示空前缀) - 每读入一个数更新
sum - 令
target = sum - x - 把
prefix_sum_unordered_map[target]加到答案上 - 再把当前
sum的计数加 1
复杂度
- 平均时间复杂度: O ( n ) O(n) O(n)
代码
cpp
#include<bits/stdc++.h>
using namespace std;
int n, x, s = 0, e = 0, sum = 0, ans = 0;
int arr[100005];
unordered_map<int, int> prefix_sum_unordered_map;
int main() {
cin >> n >> x;
prefix_sum_unordered_map[0] = 1;
for (int i = 0; i < n; i++) {
cin >> arr[i];
sum += arr[i];
int target = sum - x;
ans += prefix_sum_unordered_map[target];
prefix_sum_unordered_map[sum]++;
}
cout << ans;
return 0;
}//by wqs。