★ 算法OJ题 ★ 二分查找算法
Ciallo~(∠・ω< )⌒☆ ~ 今天,塞尔达将和大家一起做几道二分查找算法算法题 ~

❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️
澄岚主页:椎名澄嵐-ZEEKLOG博客
算法专栏:★ 优选算法100天 ★_椎名澄嵐的博客-ZEEKLOG博客
❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️
目录
贰 力扣34 - 在排序数组中查找元素的第⼀个和最后⼀个位置
壹 力扣704 - 二分查找
1.1 题目


1.2 算法解析
首先想到的暴力解法就是遍历数组,找到target,时间复杂度为O(N),那么有没有更快速的方法呢~
二分查找算法适用于有二段性的区间,比如一个值的左边比这个值小,右边比此值大,根据数学期望,中间值为最佳~


1.3 撰写代码
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) right = mid - 1; else if (nums[mid] < target) left = mid + 1; else return mid; } return -1; } };
1.4 朴素二分查找模板
while(left <= right) { int mid = left + (right - left) / 2; if (......) right = mid - 1; else if (......) left = mid + 1; else return ......; }贰 力扣34 - 在排序数组中查找元素的第⼀个和最后⼀个位置
2.1 题目
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

2.2 算法解析


2.3 撰写代码
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { // 处理数组为空 if(nums.size() == 0) return {-1, -1}; // 1. 二分左端点 int begin = 0; int left = 0, 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}; } };
2.4 二分查找模板
1. 二分左端点模板
while(left < right) { int mid = left + (right - left) / 2; if(......) left = mid + 1; else right = mid; }2. 二分右端点模板
while(left < right) { int mid = left + (right - left + 1) / 2; if(......) left = mid; else right = mid - 1; }叁 力扣35 - 搜索插入位置
3.1 题目

3.2 算法解析

3.3 撰写代码
class Solution { public: int searchInsert(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 right = mid; } if (nums[left] < target) return left + 1; else return left; } };
肆 力扣69 - x的平方根
4.1 题目

4.2 算法解析


此题需要考虑边界情况, <1单独处理~
并且数据过大有溢出风险,要用long long来存~
4.3 撰写代码
class Solution { public: int mySqrt(int x) { if(x < 1) return 0; // 边界情况~ int left = 1, right = x; while(left < right) { long long mid = left + (right - left + 1) / 2; // 防溢出 if(mid * mid <= x) left = mid; else right = mid - 1; } return left; } };
伍 力扣852 - 山峰数组的峰顶索引
5.1 题目

5.2 算法解析
5.3 撰写代码
class Solution { public: int peakIndexInMountainArray(vector<int>& arr) { int left = 1, right = arr.size() - 2; while(left < right) { int mid = left + (right - left + 1) / 2; if(arr[mid] > arr[mid - 1]) left = mid; else right = mid - 1; } return left; } };
陆 力扣162 - 寻找峰值
6.1 题目

6.2 算法解析

无序数组有二段性时也可以使用二分查找算法~
6.3 撰写代码
class Solution { public: int findPeakElement(vector<int>& nums) { int left = 0, right = nums.size() - 1; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] > nums[mid + 1]) right = mid; else left = mid + 1; } return left; } };
柒 力扣153 - 寻找旋转排序数组中的最小值
7.1 题目
153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

7.2 算法解析

7.3 撰写代码
class Solution { public: int findMin(vector<int>& nums) { int left = 0, right = nums.size() - 1; int n = nums[right]; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] > n) left = mid + 1; else right = mid; } return nums[left]; } };
捌 力扣LCR173 - 点名
8.1 题目

8.2 算法解析

8.3 撰写代码
class Solution { public: int takeAttendance(vector<int>& records) { int left = 0, right = records.size() - 1; while (left < right) { int mid = left + (right - left) / 2; if (records[mid] == mid) left = mid + 1; else right = mid; } if(records[left] == left) return left + 1; else return left; } };
