算法综合篇专题三:二分法

news/2025/3/15 6:45:38/

bf1f8397c9d44264b5443464559ec884.jpeg

"寻一颗,未萌的渺小啊,随着青翠未来,升入辽阔云霄~" 


        现在你有一个"升序"数组,想让你在这个数组里完成查找数字n,在这个数组内的下标,你可以怎么做?这也许是不少友子们初遇二分问题的场景。你可以使用O(N)的时间复杂度,对该数组进行遍历,就像这样。

void FindNum(vector<int>& arr,int n)
{for(int i=0;i<arr.size();++i){if(arr[i] == n) return i;}return -1;
}

        可是我们没有很好地利用到数组“有序”的特点,我们可以令数字为mid,那么借着有序的特点,可以将这个数组划分为两个区域,一边是小于mid的数,一边是大于mid的数。

void FindNum(vector<int>& arr,int n)
{int left = 0,right = arr.size()-1;while(left < right){int mid = (left + right) / 2;if(arr[mid] < n) mid = left+1;else if(arr[mid] > m ) mid = right-1;else mid;}return -1;
}

        所以,按照这样的算法查找数组中的某个数,时间复杂度可以下降为O(logN),是一个特别大的提升,但使用这个算法的前前提的 “数组有序”。

——前言

1、二分查找

(1) 题目解析        f9a3f845bb3b42d1bb3e95c62a56779c.png

        这道题是最朴素的二分查找,同前言举的例子是一样的解题思路。

 

(2) 算法原理        

d0056ce375774868b00a1223b6035f8e.png

class Solution {
public:int search(vector<int>& nums, int target) {int left = 0,right = nums.size()-1;// 当left==right时 当前元素是没有判断的// 因此这里需要再循环一次while(left <= right){int mid = (left + right) / 2;if(nums[mid] > target){right = mid - 1;}else if(nums[mid] < target){left = mid + 1;}else return mid;}return -1;}
};

 


 

2、在排序数组中查找元素的第⼀个和最后⼀个位置

(1) 题目解析

31e02142d2b44dfeaf3533c880c94c9f.png

        根据数组"非递减顺序" 使用二分查找但朴素的二分查找只适用于查找一个数,所以这道题需要变形。


(2) 算法原理        bee3964a73014e459e951d3ce5b9467d.png

        查找区间右端点也是类似过程,只是需要注意细节处理:

e9b4f7b024fa484c93c2f16673eb3ef3.png

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {if(nums.empty()) return {-1,-1};int left = 0,right = nums.size()-1;vector<int> ret;// 找左端点while(left < right){int mid = left + (right - left) / 2;if(nums[mid] < target){left = mid + 1;}else right = mid;}// 此时找到了左端点if(nums[left] != target) ret.push_back(-1);else ret.push_back(left);right = nums.size()-1;// 找右端点while(left < right){int mid = left + (right - left + 1) /2;if(nums[mid] > target){right = mid - 1;}else left = mid;}if(nums[right] != target) ret.push_back(-1);else ret.push_back(right);return ret;}
};

 

3、搜索插⼊位置

(1) 题目解析

098af4949fcd4dc6821c14f9fc9b4cf8.png

        这道题可以使用左端点和右端点解决。

(2) 算法原理

722822375de941c0b5911f36e3a9dd84.png

左端点:

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;return left;}
};

右端点:

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 + 1) / 2;if(nums[mid] > target){right = mid - 1;}else left = mid;}// 可能该数不存在并且 > 当前数if(nums[left] < target) return left + 1;return left;}
};

       


 

4. x 的平方根 

(1) 题目解析         0581cd0a3b844e88adeb4ba2a391fea6.png

 

(2) 算法原理        4e5a1bd44eae4391b2c0a77bbc8c048b.png

class Solution {
public:int mySqrt(int x) {if(x < 1) return 0;// 1~xint left = 1,right = x;while(left < right){int mid = left + (right -left + 1) / 2;if(x < pow(mid,2)){right = mid - 1;}else left = mid;}return left;}
};

 

5、山脉数组的峰顶索引

(1) 题目解析

18e121e9c9254959ac3597d139e5efa2.png

        

(2) 算法原理

2f7134c2f8374765ad370b7344f64045.png

左端点:

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left = 1,right = arr.size()-2;// [left,mid] [mid+1,right]while(left < right){int mid = left + (right - left) / 2;// 左端点if(arr[mid] < arr[mid+1]){left = mid + 1;}else right = mid;}return right;}
};

 

右端点: 

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left = 1,right = arr.size()-2;// [left,mid] [mid+1,right]while(left < right){int mid = left + (right - left + 1) / 2;if(arr[mid] < arr[mid-1]){right = mid - 1;}else left = mid;}return left;}
};

6、寻找峰值 

(1) 题目解析

8c385c411aa546dab34c7ce0f00c9921.png

 

(2) 算法原理         15ba960526754aaeb048145681e8c555.png

class Solution {
public:int findPeakElement(vector<int>& nums) {if(nums.size() == 1) return 0;  int left = 0,right = nums.size() - 1;while(left < right){// 左端点发int mid = left + (right - left) / 2;if(nums[mid] < nums[mid+1]){left = mid+1;}else right = mid;}return left;}
};

 


 

7、寻找旋转排序数组中的最小值

(1) 题目解析

83f6ac6ebff14fb8befd700ce9b59604.png
        如何找到本题的二段性是比较难点。

 

(2) 算法原理

        72dfd2a58eeb41398f0fe71bd26c26ae.png

class Solution {
public:int findMin(vector<int>& nums) {int left = 0,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];}
};

 


8、II. 0~n-1中缺失的数字

(1) 题目解析

c4ecbe361f0f4c85b4c343eb8dbfc8bf.png

 

(2) 算法原理        

class Solution {
public:int missingNumber(vector<int>& nums) {int left = 0,right = nums.size()-1;while(left < right){int mid = left + (right-left) / 2;if(nums[mid] == mid) {left = mid + 1;}else right = mid;}// left为0时 特殊处理return  left == nums[left] ? left+1:left;}
};

本篇到此结束,感谢你的阅读。

祝你好运,向阳而生~

d6af3a90a3034d789408339d5d1ed37e.jpeg

 


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

相关文章

L1-002 打印沙漏分数 20

L1-002 打印沙漏 分数 20 全屏浏览题目 切换布局 作者 陈越 单位 浙江大学 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”&#xff0c;要求按下列格式打印 ************ *****所谓“沙漏形状”&#xff0c;是指每行输出奇数个符号&#xff1b;各行符…

项目系列之登录管理

登录管理是现代计算机系统中关键的组成部分之一。那么本篇博客我们来简单了解一下登录的流程与前后端干了啥事。 一.登录流程&#xff1a; 用户打开登录页面&#xff1a; 用户访问应用程序或网站的登录页面。此页面通常包含用户名/邮箱输入字段和密码输入字段&#xff0c;以及…

E. Non-Decreasing Dilemma

Problem - E - Codeforces 思路&#xff1a;看这个题的输入输出格式很容易能够想到线段树&#xff0c;一开始想了一个用三个线段树的方法&#xff0c;写了500多行&#xff0c;但是wa了&#xff0c;不太好调&#xff0c;看题解发现想复杂了&#xff0c;其实挺简单&#xff0c;我…

SEO和SEM的区别与联系:优化和推广的艺术

SEO和SEM的区别与联系&#xff1a;优化和推广的艺术 在当今商业竞争日益激烈的市场环境下&#xff0c;企业对于网站的建设和管理越来越重视。为了吸引更多的潜在客户&#xff0c;企业不得不花费大量时间和资源来进行SEO优化和SEM推广。虽然二者都是提高网站流量的有效方法&…

gpcopy命令详解

注&#xff1a;本文部分翻译自https://docs.vmware.com/en/VMware-Greenplum-Data-Copy-Utility/2.6/greenplum-copy/gpcopy.html gpcopy实用程序将对象从源Greenplum数据库系统中的数据库复制到目标Greenplum数据库系统中的数据库。 语法 gpcopy{ {-F | --full} |{ {-d | -…

Leaflet入门,原生html网页如何使用Leaflet地图

前言 本章讲解如何不使用vue或react的情况下,在原生html网页中使用Leaflet地图加载地图的功能。 以高德地图xyz瓦片地图为例。 示例演示效果 vue如何使用Leaflet vue2如何使用:《Leaflet入门,如何使用vue2-leaflet实现vue2双向绑定式的使用Leaflet地图,以及初始化后拿到…

Rocky Linux切换yum源

AlmaLinux OS和Rocky Linux切换yum源 Rocky Linux切换yum源 默认情况下&#xff0c;Rocky Linux使用CentOS的官方yum源&#xff0c;但是由于CentOS 8的停止支持&#xff0c;用户可能需要切换到其他可用的yum源。以下是切换yum源的步骤&#xff1a; 备份当前的yum源配置文件 …

【深入理解Linux锁机制】五、衍生自旋锁

系列文章: 我的圈子:高级工程师聚集地 【深入理解Linux锁机制】一、内核锁的由来 【深入理解Linux锁机制】二、中断屏蔽 【深入理解Linux锁机制】三、原子操作 【深入理解Linux锁机制】四、自旋锁 【深入理解Linux锁机制】五、衍生自旋锁 【深入理解Linux锁机制】六、信…