别再死记硬背二分法了!用C++ STL的lower_bound/upper_bound实战刷题(附LeetCode真题)

张开发
2026/4/21 22:09:29 15 分钟阅读

分享文章

别再死记硬背二分法了!用C++ STL的lower_bound/upper_bound实战刷题(附LeetCode真题)
别再死记硬背二分法了用C STL的lower_bound/upper_bound实战刷题附LeetCode真题二分查找是算法学习中的经典内容但很多C开发者在实际刷题时仍然坚持手写二分法不仅容易出错还浪费了标准库提供的强大工具。本文将带你跳出传统二分法的思维定式掌握std::lower_bound、std::upper_bound和std::binary_search的实战技巧让你的LeetCode代码更简洁、更高效。1. 为什么选择STL二分工具而非手写实现在LeetCode的二分查找题目中我们经常需要处理各种边界条件和特殊情况。手写二分法虽然能加深对算法的理解但在实际工程和竞赛中STL提供的二分工具具有明显优势减少错误手写二分法容易在边界条件、循环终止条件和中间值计算上出错代码简洁STL函数一行代码即可完成复杂查找逻辑性能保证STL实现经过高度优化效率不输手写版本语义清晰函数名直接表达查找意图如lower_bound表示查找第一个不小于目标值的位置// 手写二分查找 vs STL实现对比 int binary_search_manual(vectorint nums, int target) { int left 0, right nums.size() - 1; while (left right) { int mid left (right - left) / 2; if (nums[mid] target) left mid 1; else if (nums[mid] target) right mid - 1; else return mid; } return -1; } // 使用STL的binary_search bool stl_binary_search(vectorint nums, int target) { return binary_search(nums.begin(), nums.end(), target); }提示STL二分查找函数的时间复杂度均为O(log n)与手写实现相同但更不容易出错。2. STL二分查找三剑客详解2.1 std::binary_search基础存在性检查std::binary_search是最简单的二分查找工具用于判断元素是否存在于有序范围内vectorint nums {1, 3, 5, 7, 9}; bool found binary_search(nums.begin(), nums.end(), 5); // true bool not_found binary_search(nums.begin(), nums.end(), 4); // false适用场景只需要知道元素是否存在不关心具体位置快速判断某个值是否在候选列表中2.2 std::lower_bound查找第一个不小于目标的位置std::lower_bound返回第一个不小于目标值的位置是解决LeetCode二分问题的利器vectorint nums {1, 2, 2, 3, 4, 4, 4, 5}; auto it lower_bound(nums.begin(), nums.end(), 3); // it指向第一个3索引为3关键特性如果目标值存在返回第一个等于目标的位置如果目标值不存在返回第一个大于目标的位置如果所有元素都小于目标返回end()2.3 std::upper_bound查找第一个大于目标的位置std::upper_bound返回第一个大于目标值的位置常与lower_bound配合使用vectorint nums {1, 2, 2, 3, 4, 4, 4, 5}; auto it upper_bound(nums.begin(), nums.end(), 3); // it指向第一个4索引为4典型应用计算某个值在有序数组中的出现次数确定插入位置以保持有序性3. LeetCode真题实战解析3.1 例题1在排序数组中查找元素的第一个和最后一个位置LeetCode 34这是典型的lower_bound和upper_bound应用场景vectorint searchRange(vectorint nums, int target) { auto left lower_bound(nums.begin(), nums.end(), target); if (left nums.end() || *left ! target) return {-1, -1}; auto right upper_bound(nums.begin(), nums.end(), target); return {static_castint(left - nums.begin()), static_castint(right - nums.begin() - 1)}; }解题要点先用lower_bound找到第一个等于target的位置检查是否真的找到可能不存在用upper_bound找到第一个大于target的位置返回两个位置的索引3.2 例题2搜索插入位置LeetCode 35这道题可以直接用lower_bound解决int searchInsert(vectorint nums, int target) { return lower_bound(nums.begin(), nums.end(), target) - nums.begin(); }注意lower_bound的返回值正好就是目标值应该插入的位置无论目标值是否存在。3.3 例题3寻找峰值LeetCode 162虽然题目描述不是典型的二分查找但可以用二分思想结合STL工具解决int findPeakElement(vectorint nums) { auto it max_element(nums.begin(), nums.end()); return it - nums.begin(); }优化思路对于更复杂的峰值查找可以结合adjacent_find等STL算法。4. 高级技巧与常见陷阱4.1 自定义比较函数STL二分工具支持自定义比较函数可以处理复杂数据结构struct Item { int id; string name; }; vectorItem items {{1, apple}, {2, banana}, {3, orange}}; auto it lower_bound(items.begin(), items.end(), 2, [](const Item item, int id) { return item.id id; });4.2 处理降序数组默认情况下STL二分工具适用于升序数组降序数组需要调整比较逻辑vectorint nums {5, 4, 3, 2, 1}; auto it lower_bound(nums.begin(), nums.end(), 3, greaterint());4.3 常见错误与调试技巧未排序数据使用前必须确保数据已排序否则结果不可预测错误的范围确保begin和end参数正确表示搜索范围迭代器失效在修改容器后之前获取的迭代器可能失效类型不匹配自定义比较函数需确保参数类型一致// 错误示例未排序数据 vectorint nums {3, 1, 4, 2}; auto it lower_bound(nums.begin(), nums.end(), 2); // 未定义行为 // 正确做法先排序 sort(nums.begin(), nums.end()); it lower_bound(nums.begin(), nums.end(), 2); // 正确在实际项目中我发现很多开发者会忽略STL二分工具的存在坚持手写实现。但在处理复杂边界条件时STL工具往往能提供更可靠的解决方案。特别是在时间紧迫的竞赛或面试中直接使用这些工具可以大幅减少调试时间。

更多文章