赞
踩
序言:
目录
二分查找算法(Binary Search Algorithm)是一种在有序数组中查找目标值的高效算法。它的基本思想是将数组分成两部分,然后通过比较目标值和数组的中间元素,确定目标值可能存在的位置,然后将搜索范围缩小一半,逐步逼近目标值的位置,直到找到目标值或确定目标值不存在。
以下是二分查找算法的详细过程:
二分查找算法的时间复杂度为 O(log n),其中 n 是数组的大小。由于每次都将搜索范围缩小一半,因此算法的效率非常高。
二分查找算法的前提是数组必须是有序的,如果数组无序,则需要先进行排序操作。此外,二分查找算法还可用于在旋转有序数组中查找目标值,只需要在比较大小时增加一些额外的判断条件。
需要注意的是,二分查找算法适用于静态数组或只读的情况。如果需要频繁地插入或删除元素,会导致数组的重新排序,影响二分查找的优势。
【小结】
接下来,我们通过具体的题目带着大家去进行理解相关算法。
【算法思路】
【寻找左边界思路】
寻找左边界:
◦ 我们注意到以左边界划分的两个区间的特点:
• 因此,关于 mid 的落点,我们可以分为下⾯两种情况:
• 由此,就可以通过⼆分,来快速寻找左边界;
注意:这⾥找中间元素需要向下取整
因为后续移动左右指针的时候:
- 左指针: left = mid + 1 ,是会向后移动的,因此区间是会缩⼩的;
- 右指针: right = mid ,可能会原地踏步(⽐如:如果向上取整的话,如果剩下 1,2 两个元素, left == 1 , right == 2 , mid == 2 。更新区间之后, left,right,mid 的值没有改变,就会陷⼊死循环)
因此⼀定要注意,当 right = mid 的时候,要向下取整。
【寻找右边界思路】
寻右左边界:
◦ ⽤ resRight 表⽰右边界;
◦ 我们注意到右边界的特点:
• 因此,关于 mid 的落点,我们可以分为下⾯两种情况:
• 由此,就可以通过⼆分,来快速寻找右边界;
注意:这⾥找中间元素需要向上取整
因为后续移动左右指针的时候:
- 左指针: left = mid ,可能会原地踏步(⽐如:如果向下取整的话,如果剩下 1,2 两个元素, left == 1, right == 2,mid == 1 。更新区间之后, left,right,mid 的值没有改变,就会陷⼊死循环)。
- 右指针: right = mid - 1 ,是会向前移动的,因此区间是会缩⼩的;
因此⼀定要注意,当 right = mid 的时候,要向下取整。
【代码展示】
- 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;
- int right = nums.size() - 1;
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(nums[mid] < target) left = mid + 1;
- else right = mid;
- }
-
- // 判断是否有结果
- if(nums[left] != target)
- return {-1, -1};
- else
- begin = left; // 标记⼀下左端点
-
- // 2. ⼆分右端点
- left = 0, right = nums.size() - 1;
- while(left < right)
- {
- int mid = left + (right - left + 1) / 2;
- if(nums[mid] <= target) left = mid;
- else right = mid - 1;
- }
- return {begin, right};
- }
- };
【解释说明】
在边界情况下,如果给定的数组为空,则直接返回结果为{-1, -1}。
创建一个变量来记录结果的左端点。begin
初始化左右指针和分别指向数组的起始位置和末尾位置。left
right
第一个while循环是为了找到目标值的左端点,使用二分查找的思想。
mid =
(left + right) / 2
right =
mid
left =
right
判断是否等于目标值,如果不等于,则说明目标值不存在于数组中,返回结果为{-1, -1}。nums[left] =
target
否则,标记左端点位置为。begin =
left
第二个while循环是为了找到目标值的右端点,同样使用二分查找的思想。
mid =
(left + right + 1) / 2
right =
mid - 1
left =
right
返回结果为{, },即目标值的范围。
【性能分析】
【算法思路】
题⽬中的数组规则如下图所⽰:
其中 C 点就是我们要求的点。
⼆分的本质:找到⼀个判断标准,使得查找区间能够⼀分为⼆。
通过图像我们可以发现, [A,B] 区间内的点都是严格⼤于 D 点的值的, C 点的值是严格⼩
于 D 点的值的。但是当 [C,D] 区间只有⼀个元素的时候, C 点的值是可能等于 D 点的值。
因此,初始化左右两个指针 left , right :
然后根据 mid 的落点,我们可以这样划分下⼀次查询的区间:
当区间⻓度变成 1 的时候,就是我们要找的结果
【代码展示】
- class Solution {
- public:
- int findMin(vector<int>& nums) {
- int left = 0;
- int right = nums.size() - 1;
- int x = nums[right]; // 标记⼀下最后⼀个位置的值
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(nums[mid] > x) left = mid + 1;
- else right = mid;
- }
- return nums[left];
- }
- };
【解释说明】
初始化左右指针和分别指向数组的起始位置和末尾位置。left
right
创建一个变量来存储数组最后一个位置上的值,即数组中的最大值。这是为了标记最后一个位置的值,以便在最后返回最小值。x
nums[right]
进入while循环,判断条件是,即左指针小于右指针时执行循环。left < right
将中间位置的索引计算为,这是一个向下取整的操作。mid
(left + right) / 2
比较中间位置的元素和最后一个位置的值。nums[mid]
x
循环结束后,返回,即找到的最小值。nums[left]
【性能分析】
【算法思路】
1、初始化两个指针,一个指针指向二维矩阵的左上角,即第一行第一列的元素,另一个指针指向二维矩阵的右下角,即最后一行最后一列的元素。利用这两个指针来缩小搜索范围。
2、在每次循环中,首先比较左上角指针所指的元素与目标值的关系:
3、重复步骤5,直到左上角指针的行数大于右下角指针的行数或者左上角指针的列数大于右下角指针的列数,表示搜索范围已经缩小到无法再继续缩小的情况
【代码实现】
- class Solution {
- public:
- bool searchMatrix(vector<vector<int>>& matrix, int target) {
- if (matrix.empty() || matrix[0].empty())
- {
- return false;
- }
-
- int m = matrix.size();
- int n = matrix[0].size();
-
- int left = 0;
- int right = m * n - 1;
-
- while (left <= right)
- {
- int mid = left + (right - left) / 2;
- int row = mid / n;
- int col = mid % n;
-
- if (matrix[row][col] == target)
- {
- return true;
- }
- else if (matrix[row][col] < target)
- {
- left = mid + 1;
- }
- else
- {
- right = mid - 1;
- }
- }
-
- return false;
- }
- };
【解释说明】
首先检查矩阵是否为空,如果是空矩阵,则直接返回。
获取矩阵的行数和列数。
初始化左指针为0,右指针为矩阵总元素数减1。
进入while循环,判断条件是,即左指针小于等于右指针时执行循环。left <= right
计算中间位置的索引,使用进行计算。mid=
(left + right) / 2
根据中间索引计算出对应的行和列,通过和分别得到行和列的值。
将矩阵中对应的元素与目标值进行比较。
循环结束后,如果没有找到目标值,返回。
【性能分析】
请⼤家⼀定不要觉得背下模板就能解决所有⼆分问题。⼆分问题最重要的就是要分析题意,然后确定要搜索的区间,根据分析问题来写出⼆分查找算法的代码。
重要的事情说三遍。
【模板记忆技巧】
以上便是关于 二分查找 算法的全部知识讲解!大家多加练习,立即这部分算法还是很轻松的!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。