当前位置: 首页 > news >正文

二分查找算法 (典型算法思想)—— OJ例题算法解析思路

目录

一、704. 二分查找 - 力扣(LeetCode)

运行代码:

 1. 核心思想

2. 代码思路

初始化

循环条件

计算中间位置

比较中间值与目标值

未找到目标值

3. 关键点

4. 示例

二、34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

运行代码: 

1. 核心思想

2. 代码思路

边界情况处理

第一次二分查找:查找起始位置(左端点)

第二次二分查找:查找结束位置(右端点)

3. 关键点

4. 示例

5. 代码总结

超级重点:

1. 第一次二分查找:查找起始位置(左端点)

目标

实现逻辑

为什么这样设计?

示例

2. 第二次二分查找:查找结束位置(右端点)

目标

实现逻辑

为什么这样设计?

示例

3. 总结两次二分查找的差异

4. 为什么不能统一写法?

5. 示例分析

6. 结论

三、35. 搜索插入位置 - 力扣(LeetCode)

运行代码: 

1. 核心思想

2. 代码思路

初始化

二分查找

循环结束后的处理

3. 关键点

4. 示例

示例 1:

示例 2:

示例 3:

四、69. x 的平方根 - 力扣(LeetCode)

方法一:暴力查找

运行代码: 

方法二:二分查找算法

运行代码:

1. 边界情况处理

2. 二分查找

3. 循环查找

4. 终止条件

5. 返回结果

总结

五、852. 山脉数组的峰顶索引 - 力扣(LeetCode)

运行代码: 

1. 初始化指针

2. 二分查找循环

3. 返回结果

关键点解析

示例验证

复杂度

六、162. 寻找峰值 - 力扣(LeetCode)

运行代码: 

1. 初始化指针

2. 二分查找循环

3. 返回结果

关键点解析

示例验证

复杂度

七、153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

 运行代码:

1. 初始化指针

2. 二分查找循环

3. 返回结果

关键点解析

示例验证

复杂度

八、LCR 173. 点名 - 力扣(LeetCode)

运行代码: 

1. 初始化指针

2. 二分查找循环

3. 返回结果

关键点解析

示例验证

复杂度


一、704. 二分查找 - 力扣(LeetCode)

运行代码:

class Solution {
public:int search(vector<int>& 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;}
};

 1. 核心思想

二分查找的核心思想是通过分治策略,每次将搜索区间缩小一半,从而快速定位目标值。它的时间复杂度是 O(log n),效率非常高。


2. 代码思路

初始化
  • left 和 right 分别表示当前搜索区间的左右边界。

    • left = 0:初始左边界,指向数组的第一个元素。

    • right = nums.size() - 1:初始右边界,指向数组的最后一个元素。

循环条件
  • while (left <= right)

    • 当 left <= right 时,说明当前搜索区间仍然有效,可以继续查找。

    • 如果 left > right,说明搜索区间已经无效,目标值不存在,退出循环并返回 -1

计算中间位置
  • int mid = left + (right - left) / 2

    • 计算当前区间的中间位置 mid

    • 使用 left + (right - left) / 2 而不是 (left + right) / 2,是为了避免 left + right 可能导致的整数溢出问题。

比较中间值与目标值
  • if (nums[mid] < target)

    • 如果中间值小于目标值,说明目标值在右半部分,更新左边界 left = mid + 1

  • else if (nums[mid] > target)

    • 如果中间值大于目标值,说明目标值在左半部分,更新右边界 right = mid - 1

  • else

    • 如果中间值等于目标值,说明找到了目标值,直接返回 mid(目标值的索引)。

未找到目标值
  • 如果循环结束仍未找到目标值,返回 -1,表示目标值不存在于数组中。


3. 关键点

  1. 有序数组

    • 二分查找的前提是数组必须是有序的(升序或降序)。如果数组无序,需要先排序。

  2. 区间更新

    • 每次比较后,区间会被缩小一半:

      • 如果 nums[mid] < target,目标值在右半部分,更新 left = mid + 1

      • 如果 nums[mid] > target,目标值在左半部分,更新 right = mid - 1

  3. 循环条件

    • left <= right 确保在 left == right 时仍然检查最后一个可能的元素。

  4. 返回值

    • 找到目标值时返回其索引。

    • 未找到时返回 -1


4. 示例

假设数组为 [1, 2, 3, 4, 5],目标值为 4

  1. 初始区间:left = 0right = 4

  2. 第一次循环:

    • mid = 2nums[mid] = 3

    • 3 < 4,更新 left = 3

  3. 第二次循环:

    • mid = 3nums[mid] = 4

    • 找到目标值,返回 3

二、34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

运行代码: 

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {// 处理边界情况if (nums.size() == 0)return {-1, -1};int begin = 0;// 1. ⼆分左端点int left = 0, right = nums.size() - 1;while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] < target)left = mid + 1;elseright = mid;}// 判断是否有结果if (nums[left] != target)return {-1, -1};elsebegin = left; // 标记⼀下左端点// 2. ⼆分右端点left = 0, right = nums.size() - 1;while (left < right) {int mid = left + (right - left + 1) / 2;if (nums[mid] <= target)left = mid;elseright = mid - 1;}return {begin, right};}
};

1. 核心思想

  • 使用两次二分查找

    1. 第一次二分查找目标值的起始位置(左端点)。

    2. 第二次二分查找目标值的结束位置(右端点)。

  • 通过两次二分查找,可以高效地找到目标值的区间范围。


2. 代码思路

边界情况处理
  • 如果数组为空(nums.size() == 0),直接返回 {-1, -1},因为目标值不可能存在于空数组中。

第一次二分查找:查找起始位置(左端点)
  • 初始化:

    • left = 0right = nums.size() - 1

  • 循环条件:

    • while (left < right):当 left == right 时,退出循环。

  • 计算中间位置:

    • int mid = left + (right - left) / 2

  • 比较中间值与目标值:

    • 如果 nums[mid] < target,说明目标值在右半部分,更新 left = mid + 1

    • 否则(nums[mid] >= target),说明目标值在左半部分或当前位置就是起始位置,更新 right = mid

  • 判断是否找到目标值:

    • 如果 nums[left] != target,说明目标值不存在,返回 {-1, -1}

    • 否则,记录起始位置 begin = left

第二次二分查找:查找结束位置(右端点)
  • 初始化:

    • left = 0right = nums.size() - 1

  • 循环条件:

    • while (left < right):当 left == right 时,退出循环。

  • 计算中间位置:

    • int mid = left + (right - left + 1) / 2

      • 这里 +1 是为了避免死循环(当 left 和 right 相邻时,mid 会偏向右侧)。

  • 比较中间值与目标值:

    • 如果 nums[mid] <= target,说明目标值在右半部分或当前位置就是结束位置,更新 left = mid

    • 否则(nums[mid] > target),说明目标值在左半部分,更新 right = mid - 1

  • 返回结果:

    • 返回 {begin, right},其中 begin 是起始位置,right 是结束位置。


3. 关键点

  1. 两次二分查找

    • 第一次查找目标值的起始位置。

    • 第二次查找目标值的结束位置。

  2. 查找起始位置

    • 当 nums[mid] >= target 时,更新 right = mid,因为目标值可能在左半部分或当前位置就是起始位置。

  3. 查找结束位置

    • 当 nums[mid] <= target 时,更新 left = mid,因为目标值可能在右半部分或当前位置就是结束位置。

    • 计算 mid 时 +1,是为了避免死循环。

  4. 边界条件

    • 如果数组为空,直接返回 {-1, -1}

    • 如果第一次二分查找未找到目标值,直接返回 {-1, -1}


4. 示例

假设数组为 [5, 7, 7, 8, 8, 10],目标值为 8

  1. 第一次二分查找(起始位置)

    • 初始区间:left = 0right = 5

    • 第一次循环:

      • mid = 2nums[mid] = 7

      • 7 < 8,更新 left = 3

    • 第二次循环:

      • mid = 4nums[mid] = 8

      • 8 >= 8,更新 right = 4

    • 第三次循环:

      • left == right,退出循环。

    • 检查 nums[left] == 8,记录起始位置 begin = 3

  2. 第二次二分查找(结束位置)

    • 初始区间:left = 0right = 5

    • 第一次循环:

      • mid = 3nums[mid] = 8

      • 8 <= 8,更新 left = 3

    • 第二次循环:

      • mid = 4nums[mid] = 8

      • 8 <= 8,更新 left = 4

    • 第三次循环:

      • mid = 5nums[mid] = 10

      • 10 > 8,更新 right = 4

    • 退出循环,返回 {3, 4}


5. 代码总结

这是一种高效且经典的解决有序数组中查找目标值区间的方法,时间复杂度为 O(log n)

超级重点:


http://www.mrgr.cn/news/89788.html

相关文章:

  • QT修仙之路1-1--遇见QT
  • 汇编语言运行环境搭建及简单使用
  • sudoers文件修改格式错误恢复
  • 数据流中的第 K 大元素(703)
  • Nginx在Linux中的最小化安装方式
  • Python----Python高级(函数基础,形参和实参,参数传递,全局变量和局部变量,匿名函数,递归函数,eval()函数,LEGB规则)
  • MFC 学习笔记目录
  • 车型检测7种YOLOV8
  • 订单状态监控实战:基于 SQL 的状态机分析与异常检测
  • 制造业设备状态监控与生产优化实战:基于SQL的序列分析与状态机建模
  • Denavit-Hartenberg DH MDH坐标系
  • 深入解析 COUNT(DISTINCT) OVER(ORDER BY):原理、问题与高效替代方案
  • 芯片AI深度实战:让verilog不再是 AI 的小众语言
  • SQL进阶实战技巧:某芯片工厂设备任务排产调度分析 | 间隙分析技术应用
  • android 音视频系列引导
  • (●ˇ∀ˇ●)思维导图计划~~~
  • 【动态规划】杨表
  • Ollama 使用笔记
  • 傅立叶变换、拉普拉斯变换、Z 变换的联系是什么?为什么要进行这些变换?
  • FPGA自分频产生的时钟如何使用?
  • [实战]Ubuntu使用工具和命令无法ssh,但使用另一台Ubuntu机器可以用命令ssh,非root用户。
  • AI-Talk开发板之替换唤醒词
  • 商用车电子电气零部件电磁兼容条件和试验—目录
  • 使用rknn进行retinaface部署(C++)
  • 202309 青少年软件编程等级考试C/C++ 二级真题答案及解析(电子学会)
  • Yocto构建Qt ARM64工具链