c++ 二分查找

news/2024/11/14 6:15:43/

二分法(Binary Search)是一种高效的查找算法,它在有序数组中查找一个元素,利用分治法的思想将查找空间逐步缩小一半。二分法的时间复杂度是 O(log n),比起线性查找(O(n))要高效得多。

基本思想

  1. 首先确定一个范围(通常是数组的左右边界)。
  2. 计算范围的中间位置。
  3. 如果中间位置的元素是目标元素,则返回该位置。
  4. 如果中间位置的元素大于目标元素,则将搜索范围缩小为中间元素左侧的部分。
  5. 如果中间位置的元素小于目标元素,则将搜索范围缩小为中间元素右侧的部分。
  6. 重复这个过程直到找到目标元素或者搜索区间为空。

代码实现

普通二分查找

#include <iostream>
#include <vector>
using namespace std;int binarySearch(const vector<int>& arr, int target) {int left = 0, right = arr.size() - 1;while (left <= right) {// int mid = left + (right - left) / 2;  // 防止溢出int mid = (left + right) >> 1;if (arr[mid] == target) {return mid;  // 找到目标,返回索引}else if (arr[mid] < target) {left = mid + 1;  // 目标在右边}else {right = mid - 1;  // 目标在左边}}return -1;  // 如果没有找到目标,返回-1
}int main() {vector<int> arr = {1, 3, 5, 7, 9, 11, 13, 15};int target = 7;int index = binarySearch(arr, target);if (-1 != index) {cout << "元素 " << target << " 在数组中的位置是: " << index << endl;} else {cout << "元素 " << target << " 不在数组中。" << endl;}return 0;
}

查找插入位置

在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

// leetcode --- 35. 搜索插入位置
int searchInsert(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;int ans = nums.size();while (l <= r) {int mid = (l + r) >> 1;if (nums[mid] < target) {l = mid + 1;} else {r = mid - 1;ans = mid;}}return ans;
}

应用

查找目标值的最左位置(查找重复元素的第一个位置)

当数组中有重复元素时,二分查找可以用来找到目标值的第一个出现位置。

问题描述:

给定一个升序排列的数组 arr 和一个目标值 target,请找出 target 在数组中首次出现的位置。

#include <iostream>
#include <vector>
using namespace std;int binarySearchLeft(const vector<int>& arr, int target) {int left = 0, right = arr.size();while (left < right) {int mid = left + (right - left) / 2;// 如果当前值等于目标值,则向左侧继续查找if (arr[mid] >= target) {right = mid;} else {left = mid + 1;}}// 检查 left 是否越界或值是否等于目标if (left < arr.size() && arr[left] == target) {return left;}return -1;  // 未找到目标值
}int main() {vector<int> arr = {1, 2, 2, 2, 3, 4, 5};int target = 2;int index = binarySearchLeft(arr, target);if (index != -1) {cout << "目标值 " << target << " 首次出现在索引: " << index << endl;} else {cout << "目标值 " << target << " 不在数组中。" << endl;}return 0;
}

查找目标值的最右位置(查找重复元素的最后位置)

类似于查找最左位置,我们也可以通过二分查找来找到目标值的最后一个出现位置。

问题描述:

给定一个升序排列的数组 arr 和一个目标值 target,请找出 target 在数组中最后出现的位置。

#include <iostream>
#include <vector>
using namespace std;int binarySearchRight(const vector<int>& arr, int target) {int left = 0, right = arr.size();while (left < right) {int mid = left + (right - left) / 2;// 如果当前值等于目标值,则向右侧继续查找if (arr[mid] <= target) {left = mid + 1;} else {right = mid;}}// 检查 left 是否越界或值是否等于目标if (left - 1 >= 0 && arr[left - 1] == target) {return left - 1;}return -1;  // 未找到目标值
}int main() {vector<int> arr = {1, 2, 2, 2, 3, 4, 5};int target = 2;int index = binarySearchRight(arr, target);if (index != -1) {cout << "目标值 " << target << " 最后出现在索引: " << index << endl;} else {cout << "目标值 " << target << " 不在数组中。" << endl;}return 0;
}

查找最小的满足条件的数

有时我们需要找到某个最小的满足特定条件的数,这通常使用二分查找来优化。例如,找出第一个大于等于某个值的元素。

问题描述:

给定一个升序数组 arr 和一个目标值 target,找到第一个大于等于 target 的元素。如果没有找到,则返回 -1。

#include <iostream>
#include <vector>
using namespace std;int binarySearchLowerBound(const vector<int>& arr, int target) {int left = 0, right = arr.size();while (left < right) {int mid = left + (right - left) / 2;if (arr[mid] < target) {left = mid + 1;  // 搜索右边} else {right = mid;  // 搜索左边}}// 检查是否越界if (left < arr.size() && arr[left] >= target) {return left;}return -1;  // 没有找到满足条件的元素
}int main() {vector<int> arr = {1, 2, 4, 6, 8, 10};int target = 5;int index = binarySearchLowerBound(arr, target);if (index != -1) {cout << "第一个大于等于 " << target << " 的元素在索引: " << index << ", 值为 " << arr[index] << endl;} else {cout << "没有找到满足条件的元素。" << endl;}return 0;
}

求解旋转排序数组中的目标值

有时数组可能已经进行了旋转(比如,排序数组 arr = [4, 5, 6, 7, 0, 1, 2]),我们可以使用二分查找来找到目标值的位置。

问题描述:

给定一个旋转过的升序数组 arr 和一个目标值 target,请找出目标值在数组中的索引。如果不存在,返回 -1。

#include <iostream>
#include <vector>
using namespace std;int searchRotatedArray(const vector<int>& arr, int target) {int left = 0, right = arr.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) {return mid;  // 找到目标值}// 判断左边是否有序if (arr[left] <= arr[mid]) {if (arr[left] <= target && target < arr[mid]) {right = mid - 1;  // 目标在左边} else {left = mid + 1;  // 目标在右边}} else {// 右边有序if (arr[mid] < target && target <= arr[right]) {left = mid + 1;  // 目标在右边} else {right = mid - 1;  // 目标在左边}}}return -1;  // 未找到目标值
}int main() {vector<int> arr = {6, 7, 9, 15, 19, 2, 3};int target = 3;int index = searchRotatedArray(arr, target);if (index != -1) {cout << "目标值 " << target << " 在数组中的索引是: " << index << endl;} else {cout << "目标值 " << target << " 不在数组中。" << endl;}return 0;
}

总结

  • 时间复杂度:无论是普通的二分查找还是查找插入位置,时间复杂度都是 O(log n),其中 n 是数组的大小。

  • 适用场景:二分查找仅适用于有序数组。如果数组是无序的,必须先对其进行排序才能使用二分法


http://www.ppmy.cn/news/1546857.html

相关文章

TOEIC 词汇专题:科技硬件篇

TOEIC 词汇专题&#xff1a;科技硬件篇 在科技硬件领域中&#xff0c;有一些核心词汇能帮助大家更准确地表达设备的兼容性、功能等内容。今天我们就来学习这些词汇&#xff0c;并配上例句&#xff0c;帮助您更轻松地掌握&#xff01; 1. 设备与制造 科技硬件包括各类设备&…

Scala图书馆创建图书信息

图书馆书籍管理系统相关的练习。内容要求&#xff1a; 1.创建一个可变 Set&#xff0c;用于存储图书馆中的书籍信息&#xff08;假设书籍信息用字符串表示&#xff0c;如 “Java 编程思想”“Scala 实战” 等&#xff09;&#xff0c;初始化为包含几本你喜欢的书籍。 2.添加两本…

2.操作系统常见面试问题2

2.19 说说什么是堆栈溢出&#xff0c;会怎么样&#xff1f; 堆溢出&#xff08;Heap Overflow&#xff09;是指程序在运行时向堆内存区域写入了超出预定大小的数据&#xff0c;导致堆内存区域的数据结构&#xff08;如动态分配的内存块&#xff09;被破坏&#xff0c;从而引发…

7天用Go从零实现分布式缓存GeeCache(改进)(未完待续)

lru包 好的&#xff0c;我来为您完整地解说这段代码&#xff0c;指出其中的问题并给出改进方案。 代码分析&#xff1a; 您提供的 Add 方法用于将一个键值对添加到缓存中&#xff0c;或者更新已有的键值对。代码如下&#xff1a; // Add 将一个值添加到缓存中。 func (c *C…

Prometheus面试内容整理-Prometheus 的架构和工作原理

Prometheus 的架构设计基于分布式系统中的监控需求,能够高效地收集、存储和查询时间序列数据。它采用拉取(pull)模型、自动服务发现、数据持久化存储等方式来满足现代系统的监控和告警需求。 Prometheus 的架构 Prometheus 的架构包含多个核心组件,各自负责不同的功能模块,…

【大语言模型学习】LORA微调方法

LORA: Low-Rank Adaptation of Large Language Models 摘要 LoRA (Low-Rank Adaptation) 提出了一种高效的语言模型适应方法,针对预训练模型的适配问题: 目标:减少下游任务所需的可训练参数,降低硬件要求。方法:冻结预训练模型权重,注入低秩分解矩阵,从而在不影响推理…

微服务电商平台课程三:搭建后台服务

前言 上节课,我们一起完成基础环境搭建,这节课, 我们利用上节课搭建我们电商平台.这节课我们采用开源代码进行搭建, 不论大家后续从事什么行业,都要学会站在巨人的肩膀上. 之前所说的,整个微服务平台的技术栈也是非常多的, 由于时间和效果的关系, 我们不可能从每个技术一步一…

MyBatisPlus 用法详解

MyBatisPlus 用法详解 MyBatis-Plus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。它提供了丰富的功能&#xff0c;包括强大的CRUD操作、条件构造器、自动填充、分页插件等&…