题解:洛谷 P15799 找数
【题目来源】
洛谷:P15799 [GESP202603 五级] 找数 - 洛谷
【题目描述】
给定一个包含 \(n\) 个互不相同的正整数的数组 \(A\) 与一个包含 \(m\) 个互不相同的正整数的数组 \(B\),请你帮忙计算有多少个数在数组 \(A\) 与数组 \(B\) 中均出现。
【输入】
第一行包含两个整数 \(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\)(长度 \(n\))和 \(B\)(长度 \(m\)),需要统计同时在两个数组中出现的数的个数。本质是集合交集大小的计算问题。由于两个数组内部元素互不相同,每个数在每个数组中最多出现一次。
-
算法选择:
- 哈希表(
map)计数:将两个数组的所有元素放入同一个频率表中,出现次数为 \(2\) 的即为交集元素 - 集合交集思想:利用"元素互不相同"的条件,通过频率统计替代显式集合操作
- 哈希表(
-
关键步骤:
- 初始化:创建频率表
mp - 录入数组 \(A\):遍历 \(A\) 的每个元素 \(x\),执行
mp[x]++ - 录入数组 \(B\):遍历 \(B\) 的每个元素 \(x\),执行
mp[x]++ - 统计交集:遍历
mp中的每个键值对 \((k, v)\):- 若 \(v = 2\),说明该数在两个数组中各出现一次,
ans++
- 若 \(v = 2\),说明该数在两个数组中各出现一次,
- 输出结果:\(ans\)
- 初始化:创建频率表
-
时间/空间复杂度:
- 时间复杂度:\(O((n + m) \log(n + m))\),每次
map插入和查询为 \(O(\log(n + m))\) - 空间复杂度:\(O(n + m)\),存储所有不同元素的频率
- 时间复杂度:\(O((n + m) \log(n + m))\),每次
-
哈希表求交集的核心思想:
- 频率即交集标记:由于两个数组内部均无重复元素,若某数在两个数组中都出现,则其在
mp中的计数恰好为 \(2\)。利用这一性质,无需显式比较两个集合,通过一次频率统计即可判定交集 - 合并统计策略:将两个数组的元素统一放入一个频率表,而非分别存储再比对,减少空间开销和比较次数
- 键的唯一性:
map的键自动去重,天然适合处理"互不相同"的集合元素,避免了重复元素的干扰 - 可扩展性:若数组内部允许重复,需调整判定条件(如 \(v \geq 2\) 或使用
set去重后再统计),但本题条件简化了逻辑 - 适用于集合交集、并集、差集等基础集合运算问题,尤其是元素范围较大或离散的场景
- 频率即交集标记:由于两个数组内部均无重复元素,若某数在两个数组中都出现,则其在
【算法标签】
普及- #哈希表
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m;
int ans;
// 使用 map 记录每个数字出现的次数
map<int, int> mp;
int main()
{
cin >> n >> m;
// 读入第一个集合的元素
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
// 记录第一个集合中数字的出现次数
mp[x]++;
}
// 读入第二个集合的元素
for (int i = 1; i <= m; i++)
{
int x;
cin >> x;
// 记录第二个集合中数字的出现次数
mp[x]++;
}
// 遍历 map
for (auto x : mp)
{
// 如果某个数字出现了两次,说明在两个集合中都出现过
if (x.second == 2)
{
ans++;
}
}
// 输出交集的大小
cout << ans << endl;
return 0;
}
【运行结果】
3 5
4 2 3
3 1 5 4 6
2
浙公网安备 33010602011771号