题解:学而思编程 库存查询
【题目来源】
学而思编程:库存查询
【题目描述】
某超市有 \(n\) 件商品,每件商品都有一个价格标签,价格是 \(1\) 到 \(10000\) 之间的整数。
现在仓库管理员想快速知道:当顾客询问“价格为 \(p\) 元的商品有多少件”时,能立刻给出答案。
请你编写一个程序,根据商品价格清单,依次回答 \(m\) 次询问。
【输入】
第一行两个整数 \(n,m\),分别表示商品总数和询问次数。
第二行包含 \(n\) 个整数,表示每件商品的价格。
接下来 \(m\) 行,每行一个整数 \(p\),表示一次询问的价格。
【输出】
输出 \(m\) 行,每行一个整数,表示对应价格的商品数量。
【输入样例】
8 5
1 1 3 4 4 4 5 5
1
2
3
4
5
【输出样例】
2
0
1
3
2
【核心思想】
-
问题分析:给定 \(n\) 件商品的价格(\(1\) 到 \(10000\) 之间的整数),回答 \(m\) 次询问,每次询问价格为 \(p\) 的商品有多少件。这是一个计数数组 + 离线查询问题,关键在于预处理每个价格的出现次数,实现 \(O(1)\) 回答每次询问。
-
算法选择:
- 计数数组:
cnt[p]记录价格为 \(p\) 的商品数量 - 离线预处理:先读取所有商品价格并统计频次,再处理询问
- 计数数组:
-
关键步骤:
- 初始化:读取 \(n\)(商品总数)和 \(m\)(询问次数)
- 统计频次:
- 遍历 \(i\) 从 \(1\) 到 \(n\):
- 读取价格 \(p\)
cnt[p]++:该价格出现次数加 \(1\)
- 遍历 \(i\) 从 \(1\) 到 \(n\):
- 处理询问:
- 遍历 \(m\) 次:
- 读取查询价格 \(p\)
- 输出
cnt[p]:价格为 \(p\) 的商品数量
- 遍历 \(m\) 次:
-
时间/空间复杂度:
- 时间复杂度:\(O(n + m)\),统计频次 \(O(n)\),每次查询 \(O(1)\)
- 空间复杂度:\(O(V)\),\(V = 10000\),计数数组
cnt[1..V]
-
计数数组的核心思想:
- 值域确定性:价格范围固定为 \(1\) 到 \(10000\),可用数组直接作为下标,实现 \(O(1)\) 访问
- 查询与数据分离:先一次性统计所有频次,后续查询无需重新遍历,适合多次询问场景
- 空间换时间:用 \(O(V)\) 空间存储频次,将每次查询从 \(O(n)\) 优化到 \(O(1)\)
- 替代方案:若值域大或稀疏,可用
map或unordered_map,但数组在稠密值域下更快 - 适用于"固定值域 + 多频次查询"类问题,计数数组是最简单高效的预处理方案
【算法标签】
模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 10005; // 定义最大范围
int n, m, p, cnt[N]; // 第一个集合数量n,查询次数m,临时值p,计数数组cnt
int main() // 主函数
{
cin >> n >> m; // 输入第一个集合的元素数量和查询次数
for (int i=1; i<=n; i++) // 读取第一个集合的所有元素
{
cin >> p; // 输入一个元素
cnt[p]++; // 统计该元素的出现次数
}
while (m--) // 处理每个查询
{
cin >> p; // 输入要查询的元素
cout << cnt[p] << endl; // 输出该元素在第一个集合中出现的次数
}
return 0; // 程序正常结束
}
【运行结果】
8 5
1 1 3 4 4 4 5 5
1
2
2
0
3
1
4
3
5
2
浙公网安备 33010602011771号