2026-10-24:聚合两个时间序列。用go语言,有两个按时间先后排列且时间点不重复的二元组列表,每个二元组由时间戳和值组成。处理时,先合并两个列表里出现过的全部时间戳并去重。对于其中任意一个时间戳,如果某个列表没有该时间点的记录,就要看这个列表里是否存在比它更晚的时间点:若存在,就取其中时间最近的那个更晚时间点的值;若不存在,就按 0 计算。然后把两个列表在这个时间戳上的取值相加。最终按照时间戳从小到大的顺序输出由时间戳和相加结果组成的二元组,并且每个时间戳只出现一次。所谓严格递增,是指后一个元素总是大于前一个元素。

1 <= series1.length, series2.length <= 100000。

series1[i].length == series2[i].length == 2。

1 <= series1[i][0], series2[i][0] <= 1000000000。

1 <= series1[i][1], series2[i][1] <= 1000000000。

每个序列都按照 timestamp 严格递增排序。

输入: series1 = [[1,3],[4,1]], series2 = [[2,2],[5,2]]。

输出: [[1,5],[2,3],[4,3],[5,2]]。

解释:

时间戳

series1

series2

summedValue

1

3

2

5

2

1

2

3

4

1

2

3

5

0

2

2

因此,聚合后的序列为 [[1, 5], [2, 3], [4, 3], [5, 2]]。

题目来自力扣4001。

大体步骤如下:

第一步,准备结果数组和两个游标。
结果数组用来存放最终聚合后的时间戳和相加值。两个游标分别指向第一个序列和第二个序列的当前元素。初始时都指向各自序列的第一个元素。因为两个序列都按时间戳严格递增排列,所以可以用从前往后合并的方式处理。

第二步,只要两个序列都还有未处理的元素,就反复执行下面的比较逻辑。
每一轮同时查看两个游标当前指向的元素,分别取得它们的时间戳和值。计算这两个当前值的和,作为本轮候选的相加值。

第三步,比较两个当前时间戳的大小。
如果第一个序列当前时间戳小于第二个序列当前时间戳,那么本轮要输出的时间戳就是第一个序列的当前时间戳。
此时第一个序列在该时间戳上有明确值;第二个序列没有这个时间戳的记录,但第二个序列当前元素的时间戳比它更晚,并且由于序列递增,这个当前元素就是第二个序列中比该时间戳更晚且最近的时间戳,所以第二个序列在该时间戳上的取值就取第二个游标当前指向的值。因此相加值等于两个当前值之和。输出这个时间戳和相加值后,只把第一个序列的游标向后移动一位。

如果第一个序列当前时间戳大于第二个序列当前时间戳,处理方式对称。
本轮输出的时间戳是第二个序列的当前时间戳。第一个序列在该时间戳缺失,但第一个序列当前元素是比它更晚且最近的时间戳,所以取第一个游标当前值参与相加。输出后只把第二个序列的游标向后移动一位。

如果两个当前时间戳相等,说明两个序列在这个时间戳上都有记录。
本轮输出该时间戳,相加值就是两个当前值之和。输出后两个游标同时向后移动一位,避免重复处理同一个时间戳。

第四步,重复上述比较和输出,直到至少有一个序列的元素全部处理完。
由于每一轮都会输出两个当前时间戳中较小的那个,或者在相等时同时跳过,因此结果中的时间戳会按照从小到大排列,并且相等时间戳只会输出一次。

第五步,处理剩余元素。
当循环结束时,至少有一个序列已经处理完。如果第一个序列还有剩余元素,就把这些剩余元素依次追加到结果中;如果第二个序列还有剩余元素,也同样追加。
对于剩余序列中的某个时间戳,另一个序列已经没有任何元素,也就意味着另一个序列中不存在比该时间戳更晚的时间戳,因此另一个序列在该时间戳上的值按 0 计算。所以追加时只需要保留剩余序列自身的时间戳和值,不需要再额外加上另一个序列的值。又因为原序列本身严格递增,追加后结果仍然保持时间戳严格递增。

第六步,返回结果数组。
结果数组中每个元素都是“时间戳,相加值”的形式,时间戳只出现一次,并且严格递增。

关于复杂度:
时间复杂度是 O(n + m),其中 n 是第一个序列的长度,m 是第二个序列的长度。两个游标都只会单调向后移动,每个元素最多被处理一次,最后追加剩余元素也只会遍历一次。
额外空间复杂度方面,如果不把返回结果所占空间计入辅助空间,那么只需要两个游标等常数级变量,辅助空间是 O(1)。如果把最终返回的结果数组也计入总空间,则结果最多包含 n + m 个时间戳,总空间复杂度为 O(n + m)。

Go完整代码如下:

package main

import (
"fmt"
)

func aggregateTimeSeries(series1, series2 [][]int) (ans [][]int) {
n, m := len(series1), len(series2)
i, j := 0, 0

for i < n && j < m {
t1, t2 := series1[i][0], series2[j][0]
sum := series1[i][1] + series2[j][1]
if t1 < t2 {
ans = append(ans, []int{t1, sum})
i++
} elseif t1 > t2 {
ans = append(ans, []int{t2, sum})
j++
} else { // 相等
ans = append(ans, []int{t1, sum})
i++
j++
}
}

ans = append(ans, series1[i:]...)
ans = append(ans, series2[j:]...)
return
}

func main() {
series1 := [][]int{{1, 3}, {4, 1}}
series2 := [][]int{{2, 2}, {5, 2}}
result := aggregateTimeSeries(series1, series2)
fmt.Println(result)
}
打开网易新闻 查看精彩图片

Python完整代码如下:

# -*-coding:utf-8-*-

def aggregate_time_series(series1, series2):
ans = []
n, m = len(series1), len(series2)
i, j = 0, 0

while i < n and j < m:
t1, v1 = series1[i]
t2, v2 = series2[j]
total = v1 + v2

if t1 < t2:
ans.append([t1, total])
i += 1
elif t1 > t2:
ans.append([t2, total])
j += 1
else:
ans.append([t1, total])
i += 1
j += 1

ans.extend(series1[i:])
ans.extend(series2[j:])
return ans

def main():
series1 = [[1, 3], [4, 1]]
series2 = [[2, 2], [5, 2]]
result = aggregate_time_series(series1, series2)
print(result)

if __name__ == "__main__":
main()
打开网易新闻 查看精彩图片

C++完整代码如下:

  


using namespace std;


vector int >> aggregateTimeSeries( const vector int >>& series1,
const vector int >>& series2) {
vector int >> ans;
int n = series1.size();
int m = series2.size();
int i = 0 , j = 0 ;

while (i < n && j < m) {
int t1 = series1[i][ 0 ];
int t2 = series2[j][ 0 ];
int sum = series1[i][ 1 ] + series2[j][ 1 ];

if (t1 < t2) {
ans.push_back({t1, sum});
i++;
} else if (t1 > t2) {
ans.push_back({t2, sum});
j++;
} else { // 相等
ans.push_back({t1, sum});
i++;
j++;
}
}

ans.insert(ans.end(), series1.begin() + i, series1.end());
ans.insert(ans.end(), series2.begin() + j, series2.end());

return ans;
}

int main() {
vector int >> series1 = {{ 1 , 3 }, { 4 , 1 }};
vector int >> series2 = {{ 2 , 2 }, { 5 , 2 }};

vector int >> result = aggregateTimeSeries(series1, series2);

cout << "[" ;
for (size_t i = 0 ; i < result.size(); i++) {
if (i > 0 ) cout << ", " ;
cout << "[" << result[i][ 0 ] << ", " << result[i][ 1 ] << "]" ;
}
cout << "]" << endl;

return 0 ;
}
打开网易新闻 查看精彩图片

我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。