下面是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$ 中均出现的数的个数。

输入样例

3 5
4 2 3
3 1 5 4 6

输出样例

2

题目想让我们做什么?

你可以把这道题想象成:

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

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


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

比如:

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

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

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

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

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

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

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


举个例子

输入:

3 5
4 2 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. 用双重循环暴力比较

像这样:

for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        if (a[i] == b[j]) ans++;
    }
}

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


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

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

输出共同出现的数的个数

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


3. 把“出现”理解错

题目问的是:

AB 中都出现的数有多少个

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

参考程序

下面是一个参考实现:

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    unordered_set<int> aSet;
    int num;

    // 读入数组 A,并保存到集合中
    for (int i = 0; i < n; i++) {
        cin >> num;
        aSet.insert(num);
    }

    int count = 0;

    // 读入数组 B
    // 如果这个数也在 A 中出现过,就计数加一
    for (int i = 0; i < m; i++) {
        cin >> num;
        if (aSet.count(num)) {
            count++;
        }
    }

    cout << count << '\n';
    return 0;
}

代码讲解

1. 为什么用 unordered_set

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

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

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

所以特别适合用它。


2. 代码在做什么

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

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

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


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

int ans = 0;
for (int i = 0; i < m; i++) {
    cin >> x;
    if (s.count(x)) {
        ans++;
    }
}

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

总结

这道题的核心就是:

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

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

  • 哈希
  • 集合查找
  • 统计交集元素个数
文章分享二维码

微信扫码分享这篇文章

扫描二维码即可在手机中继续阅读,也方便转发给老师、家长或同学。

上一篇 已经是最新文章
下一篇 2026年3月 GESP C++ 4级 真题《山之谷》解析