2026年GESP C++ 5级 真题 《找数》解析

下面是2026年 GESP 5级 C++ 5级真题《找数》:


给定一个包含 $n$ 个互不相同的正整数的数组 $A$ 与一个包含 $m$ 个互不相同的正整数的数组 $B$,请你帮忙计算有多少个数在数组 $A$ 与数组 $B$ 中均出现。

数据范围

对于 $40%$ 的数据,保证 $1 \leq n,m \leq 1000$。
对于 $100%$ 的数据,保证 $1 \leq n,m \leq 10^5$,$1 \leq a_i,b_i \leq 10^9$。

输入说明

第一行包含两个整数 $n,m$。
第二行包含 $n$ 个正整数 $a_1,a_2,\cdots,a_n$ 表示数组 $A$。
第三行包含 $m$ 个正整数 $b_1,b_2,\cdots,b_m$ 表示数组 $B$。

输出说明

输出一个整数,表示在数组 $A$ 与数组 $B$ 中均出现的数的个数。

输入样例

  1. 3 5
  2. 4 2 3
  3. 3 1 5 4 6

输出样例

  1. 2

题目想让我们做什么?

你可以把这道题想象成:

  • 小明有一盒彩色卡片 A
  • 小红有一盒彩色卡片 B
  • 现在想知道:他们俩都有哪几张卡片,一共有几张

题目不是让你把这些共同的数都输出出来,而是只输出“个数”。


最容易想到的方法:一个一个比

比如:

  • 先拿 A 的第一个数,去 B 里全部找一遍
  • 再拿 A 的第二个数,去 B 里全部找一遍
  • 一直这样比较下去

这个方法能做出来,但是如果数字很多,就会特别慢。
因为:

  • A 最多有 100000 个数
  • B 最多有 100000 个数
    如果每个都去逐个比较,最多要比较:
    100000 × 100000 = 10000000000
    这是非常大的数字,OJ 很可能会超时。

更聪明的方法:先做“快速查找表”

我们先把数组 A 中的数都放进一个“快速查找盒子”里。
然后读数组 B 时:

  • 取出一个数
  • 立刻查它在不在这个盒子里
  • 如果在,就说明它在两个数组中都出现了

这个“快速查找盒子”就是 unordered_set


举个例子

输入:

  1. 3 5
  2. 4 2 3
  3. 3 1 5 4 6

第一步:把 A 放进集合

A = [4, 2, 3]
集合里就有:
{4, 2, 3}

第二步:检查 B

B = [3, 1, 5, 4, 6]
依次看:

  • 3 在集合里,答案加 1
  • 1 不在
  • 5 不在
  • 4 在集合里,答案加 1
  • 6 不在

最后答案就是 2


为什么题目特别说“互不相同”?

题目说:

  • 数组 A 中的数互不相同
  • 数组 B 中的数互不相同

这意味着:

  • A 里不会有重复数字
  • B 里也不会有重复数字

这样我们统计起来就简单了。
如果 B 里一个数字重复出现很多次,那就要额外考虑“算几次”的问题。
但这道题已经帮我们排除了这个麻烦。


五、时间复杂度

这份做法的效率

  • A 放入集合:O(n)
  • 枚举 B 并查找:O(m)

总复杂度大约是:
O(n + m)
这个速度很快,可以通过 10^5 的数据范围。


六、容易出错的地方

1. 用双重循环暴力比较

像这样:

  1. for (int i = 0; i < n; i++) {
  2. for (int j = 0; j < m; j++) {
  3. if (a[i] == b[j]) ans++;
  4. }
  5. }

虽然逻辑上没错,但数据大时会超时。


2. 忘记这题只要输出“个数”

有些同学会把共同的数字打印出来,但题目要求的是:

输出共同出现的数的个数

所以最后只输出一个整数。


3. 把“出现”理解错

题目问的是:

AB 中都出现的数有多少个

不是求和,不是找最大值,也不是找相同位置。
只要一个数字在两个数组里都出现,就算一个。

参考程序

下面是一个参考实现:

  1. #include <iostream>
  2. #include <unordered_set>
  3. using namespace std;
  4. int main() {
  5. ios::sync_with_stdio(false);
  6. cin.tie(nullptr);
  7. int n, m;
  8. cin >> n >> m;
  9. unordered_set<int> aSet;
  10. int num;
  11. // 读入数组 A,并保存到集合中
  12. for (int i = 0; i < n; i++) {
  13. cin >> num;
  14. aSet.insert(num);
  15. }
  16. int count = 0;
  17. // 读入数组 B
  18. // 如果这个数也在 A 中出现过,就计数加一
  19. for (int i = 0; i < m; i++) {
  20. cin >> num;
  21. if (aSet.count(num)) {
  22. count++;
  23. }
  24. }
  25. cout << count << '\n';
  26. return 0;
  27. }

代码执行效果可以参考我们的可视化功能,如视频所示。

<video controls preload="metadata" style="max-width:100%;">
<source src="https://qn.cncoding.cn/assets/site_images/video/video_1774384292732_zydeih.mp4" type="video/mp4">
您的浏览器暂不支持 video 标签。
</video>

代码讲解

1. 为什么用 unordered_set

unordered_set 可以理解成一个“查找特别快的集合”。
它有两个很重要的特点:

  • 可以存很多数
  • 判断一个数在不在里面,速度很快
    这题正好需要频繁判断:

“B 里的这个数,在不在 A 里?”

所以特别适合用它。


2. 代码在做什么

第一步:把 A 里的所有数存起来

  1. unordered_set<int> s;
  2. for (int i = 0; i < n; i++) {
  3. cin >> x;
  4. s.insert(x);
  5. }

比如 A = [4, 2, 3],那么集合里就有:
{4, 2, 3}


第二步:枚举 B,看看每个数是不是也在 A 里

  1. int ans = 0;
  2. for (int i = 0; i < m; i++) {
  3. cin >> x;
  4. if (s.count(x)) {
  5. ans++;
  6. }
  7. }

如果 B 中某个数也在集合 s 里,就说明它同时出现在 AB 中,答案加一。

总结

这道题的核心就是:

先把一个数组放进哈希集合,再去检查另一个数组里的每个数是否存在。

这是算法题里非常常见的一类题,属于:

  • 哈希
  • 集合查找
  • 统计交集元素个数

微信扫一扫,分享此文章

少儿编程教学平台

联系我们

微信

aguibo002

邮箱

haoxuehaojiao在163.com

Loading
我们已经收到您的信息,将尽快联系您!