洛谷 P2249 【深基13.例1】查找

博客介绍了洛谷P2249题目的解决方法,主要探讨了两种查找策略:常规版本的二分查找,运行时间为400+ms;以及经过优化的版本,运行时间降低到200+ms。通过对二分查找的优化,显著提高了搜索效率。

P2249 【深基13.例1】查找

常规版本(400+ms)

#include <iostream>
#define MAXN 1000010
using namespace std;
int a[MAXN];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n, m;
	cin >> n >> m;
	for (register int i = 0; i < n; ++i) {
		cin >> a[i];
	}
	for (register int i = 0; i < m; ++i) {
		int target;
		cin >> target;
		int l = 0;
		int r = n - 1;
		while (l <= r) {
			int mid = (l + r) >> 1;
			if (a[mid] < target) {
				l = mid + 1;
			}
			else {
				r = mid - 1;
			}
		}
		if (target == a[l]) {
			cout << (l + 1) << ' ';
		}
		else {
			cout << -1 << ' ';
		}
	}
	return 0;
}

优化版本(200+ms)


                
### 三、题目分析:洛谷 P224913.1查找 本题要求在一个**单调不减**的整数数组中,对于多个查询值,找出其**第一次出现的位置**(下标从1开始)。如果目标值不存在于数组中,则输出 `-1`。这是一道典型的考察**二分查找**应用的问题,适用于需要高效查找并处理重复元素的场景。 数组是单调不减的特性保证了可以使用二分查找来提升效率,时间复杂度为 $O(m \log n)$,其中 $m$ 是查询次数,$n$ 是数组长度[^3]。 --- ### 四、为何适用二分查找? 由于数组是有序的(即使存在重复元素),可以利用二分查找快速缩小搜索区间。标准的二分查找通常用于判断某个值是否存在,但本题还需要找到其**第一次出现的位置**,因此在本结构的础上稍作修改即可实现这一需求。 与线性查找相比,二分查找极大地提升了效率,尤其在大规模数据中表现优异。该方法也符合算法竞赛中对性能和时间限制的要求[^3]。 --- ### 五、整体解题思路 - **输入部分**:读取数组长度 `n` 和查询次数 `m`,接着读取数组和查询列表。 - **核心逻辑**:定义一个函数 `find_first(target)`,用于查找目标值在数组中第一次出现的位置。 - **二分查找策略**: - 初始化左右边界 `l = 0`, `r = n - 1`。 - 每次计算中间位置 `mid`。 - 若 `a[mid] == target`,记录当前位置,并尝试继续向左搜索以寻找更早的出现。 - 若 `a[mid] < target`,说明目标值在右半段,更新左边界。 - 否则更新右边界。 - **结果处理**:将每次查询的结果存储到列表中,最后统一输出。 --- ### 六、代码逻辑逐行解释 ```python # 读取输入的 n 和 m,分别表示数组长度和查询次数 n, m = map(int, input().split()) # 读取数组 a,表示待查询的单调不减序列 a = list(map(int, input().split())) # 读取查询列表 number,表示需要查询的数字 number = list(map(int, input().split())) # 初始化结果列表 ans,用于存储每个查询的结果 ans = [] ``` 以上部分完成数据输入操作,采用 `map` 和 `list` 快速读取多组输入,适用于竞赛环境中的高效输入方式[^3]。 ```python # 定义二分查找函数,用于找到目标值第一次出现的位置 def find_first(target): l, r = 0, n - 1 # 初始化左右边界 res = -1 # 初始化结果为 -1,表示未找到 while l <= r: mid = (l + r) // 2 # 计算中间位置 if a[mid] == target: res = mid + 1 # 记录位置(转换为从1开始的编号) r = mid - 1 # 继续在左半部分查找更早的出现 elif a[mid] < target: l = mid + 1 # 在右半部分继续查找 else: r = mid - 1 # 在左半部分继续查找 return res # 返回结果 ``` 上述函数实现了“查找第一个等于目标值”的二分查找逻辑: - 当 `a[mid] == target` 时,先记录当前索引(加1是为了适配题目输出格式),然后将右边界设为 `mid - 1`,继续向左搜索是否还有更早的匹配项。 - 如果没有找到目标值,函数最终返回 `-1`。 ```python # 对每个查询调用二分查找函数,并将结果存入 ans 列表 for i in range(m): ans.append(str(find_first(number[i]))) # 输出结果,以空格分隔 print(" ".join(ans)) ``` 最后一段代码遍历所有查询值,调用 `find_first` 函数获取结果,并将结果转换为字符串后拼接输出。 --- ### 七、总结 本题通过引入二分查找解决了在有序数组中查找第一个等于目标值的问题,体现了二分查找在处理重复元素和优化查找效率方面的优势。代码结构清晰、逻辑严谨,适合初学者学习如何在实际问题中灵活运用二分查找技巧。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值