2026-03-19:边界与内部和相等的稳定子数组。用go语言,给定一个整数数组 capacity,请统计其中有多少个连续区间符合下面的要求:
-
区间内至少包含 3 个元素;
-
这个区间的第一个数和最后一个数相同;
-
并且这两个端点的值,恰好等于它们中间所有元素的总和。
换句话说,如果某个子数组的左右两端相等,而且这个相等的值正好能被中间部分全部加起来得到,那么这个子数组就算作一个“稳定”子数组。
你的任务是:返回这样的子数组总数。
3 <= capacity.length <= 100000。
-1000000000 <= capacity[i] <= 1000000000。
输入: capacity = [9,3,3,3,9]。
输出: 2。
解释:
[9,3,3,3,9] 是稳定数组,因为首尾元素都是 9,且它们之间元素之和为 3 + 3 + 3 = 9。
[3,3,3] 是稳定数组,因为首尾元素都是 3,且它们之间元素之和为 3。
题目来自力扣3728。
一、算法整体大体过程(分步骤详细描述)
步骤1:定义核心工具
- 前缀和数组:
prefix[i]表示数组前i个元素的累加和(快速计算任意区间和); - 哈希表(字典):存储键值对,键是二元组
(当前元素值, 前缀和值),值是该二元组出现的次数; 作用:快速查找满足条件的左端点L,避免暴力遍历所有子数组。
步骤2:初始化变量
- 初始化答案计数器:用于统计符合条件的稳定子数组数量(初始为0);
- 初始化前缀和:从数组第一个元素开始计算;
- 初始化哈希表:为空,后续动态存入二元组。
步骤3:遍历数组(右指针遍历,从第二个元素开始)
以右指针r代表子数组的右端点,逐个遍历数组元素,核心逻辑分3步:
-
查询匹配的左端点 以当前右端点值
capacity[r]、当前前缀和为条件,去哈希表中查找: 有没有左端点L满足:capacity[L] = capacity[r](首尾相等);prefix[L] + capacity[L] = 前缀和(中间和等于端点值)。 查到的次数,直接累加到答案计数器中(每一次匹配都对应一个稳定子数组)。
-
存入新的二元组到哈希表 将左候选点(当前右指针的前一个元素)的二元组:
(capacity[r-1], prefix[r-1] + capacity[r-1])存入哈希表,计数+1(为后续的右端点提供匹配依据)。 -
更新前缀和 把当前元素的值加到前缀和中,继续下一轮遍历。
步骤4:遍历结束,返回答案
遍历完成后,答案计数器的值就是所有符合条件的稳定子数组数量。
二、示例推演(输入 [9,3,3,3,9])
数组索引:0(9)、1(3)、2(3)、3(3)、4(9)
目标结果:2个稳定子数组 [0,4]、[1,3]
- 初始:前缀和=9(索引0),哈希表空,答案=0;
- r=1(元素3):查询无匹配,存入
(9, 9+9=18),前缀和更新为12; - r=2(元素3):查询无匹配,存入
(3, 3+12=15),前缀和更新为15; - r=3(元素3):查询哈希表,匹配到
(3,15),答案+1(对应子数组[1,3]),存入(3,3+15=18),前缀和更新为18; - r=4(元素9):查询哈希表,匹配到
(9,18),答案+1(对应子数组[0,4]),存入新二元组,前缀和更新为27; 最终答案=2,与预期一致。
三、时间复杂度 & 额外空间复杂度
1. 时间复杂度
- 算法仅一次遍历数组,遍历次数为数组长度
n; - 哈希表的查询、插入操作都是平均 O(1) 时间;
- 总时间复杂度:O(n)
- 适配题目要求:数组长度最高10⁵,O(n)算法可高效运行。
2. 额外空间复杂度
- 仅使用了一个哈希表存储二元组;
- 哈希表最多存储
n个键值对(遍历中每个元素最多存入一次); - 无其他大规模数据结构;
- 总额外空间复杂度:O(n)
总结
- 算法核心:前缀和+哈希表,将暴力O(n²)优化为O(n);
- 过程:右指针遍历→哈希表查匹配左端点→更新答案→存入新候选→更新前缀和;
- 复杂度:时间O(n),空间O(n),完美适配大数据量的题目要求。
Go完整代码如下:
package main
import (
"fmt"
)
func countStableSubarrays(capacity []int) (ans int64) {
type pair struct{ x, s int }
cnt := map[pair]int{}
sum := capacity[0] // 前缀和
for r := 1; r < len(capacity); r++ {
ans += int64(cnt[pair{capacity[r], sum}])
cnt[pair{capacity[r-1], capacity[r-1] + sum}]++
sum += capacity[r]
}
return
}
func main() {
capacity := []int{9, 3, 3, 3, 9}
result := countStableSubarrays(capacity)
fmt.Println(result)
}
Python完整代码如下:
# -*-coding:utf-8-*-
from typing import List
from collections import defaultdict
def count_stable_subarrays(capacity: List[int]) -> int:
"""
计算稳定子数组的数量
参数:
capacity: 整数列表
返回:
稳定子数组的数量
"""
ans = 0
# 使用字典来存储pair计数,Python中的元组可以直接作为字典键
cnt = defaultdict(int)
# 前缀和
prefix_sum = capacity[0]
# 从索引1开始遍历
for r in range(1, len(capacity)):
# 查询并累加符合条件的子数组数量
ans += cnt[(capacity[r], prefix_sum)]
# 更新计数
cnt[(capacity[r-1], capacity[r-1] + prefix_sum)] += 1
# 更新前缀和
prefix_sum += capacity[r]
return ans
def main():
# 测试用例
capacity = [9, 3, 3, 3, 9]
result = count_stable_subarrays(capacity)
print(result)
if __name__ == "__main__":
main()
C++完整代码如下:
#include <iostream>
#include <vector>
#include <map>
#include <tuple>
using namespace std;
// 定义pair结构体,用于作为map的键
struct Pair {
int x; // 元素值
int s; // 和/前缀和
// 需要定义比较运算符才能作为map的键
bool operator<(const Pair& other) const {
if (x != other.x) return x < other.x;
return s < other.s;
}
};
long long countStableSubarrays(vector<int>& capacity) {
long long ans = 0;
map<Pair, int> cnt; // 使用map代替Go的map
int sum = capacity[0]; // 前缀和
for (int r = 1; r < capacity.size(); r++) {
// 查询并累加符合条件的子数组数量
ans += cnt[{capacity[r], sum}];
// 更新计数
cnt[{capacity[r-1], capacity[r-1] + sum}]++;
// 更新前缀和
sum += capacity[r];
}
return ans;
}
int main() {
// 测试用例
vector<int> capacity = {9, 3, 3, 3, 9};
long long result = countStableSubarrays(capacity);
cout << result << endl;
return 0;
}