1 二分法

参考:
《算法通关之路》
labuladong的算法小抄

1.1 二分查找

  • 二分查找又称折半搜索算法,狭义来讲,二分查找是一种在有序数组查找某一特定元素的搜索算法;广义来讲,将问题的规模缩小到原有的一半;

  • 二分查找的细节问题很多注意!

  • 术语

    • target:要查找的值;

    • index:当前位置;

    • l和r:左右指针;

    • mid:左右指针的中点,用来确定我们应该向左查找还是向右查找的索引;

  • 解空间

  • 解空间:指题目所有可能的解构成的集合;可大不可小

  • 目标:在某个具体情况下判断其具体是哪一个,如果线性枚举所有的可能,枚举部分时间复杂度就为O(n);

  • 实数二分

    • 少部分题目的解空间包括小数,会涉及精度问题,例如求一个数x的平方根,答案误差在10-6次方都认为正确,解空间大小定义为[1,x],包括所有区间的实数,不仅仅整数而已,称为实数二分;这个时候有两种变化:

      • 1)更新答案的步长:例如之前的更新是 l = mid + 1,现在可能就不行了,因此这样可能会错过正确解,比如正确解恰好就在区间 [mid,mid+1] 内的某一个小数。
      • 2)判断条件时候考虑误差:由于精度问题,判断结束条件变成与答案的误差在某一个范围内。
  • 序列有序

  • 序列有序中的序列:不一定是数组、链表、有可能是其他数据结构;

  • 有些题目没有有序关键字,比如题目给了数组nums,并且没有限定nums有序,但限定了nums为非负,如果给nums进行前缀和或前缀或(位运算或),可以得到一个有序序列。

  • 一个中心

    • 折半才是二分法的灵魂

1.2 查找一个数

  • 1、区间选取问题

    • 由于定义的搜索区间为 [left, right],因此当 left <= right 的时候,搜索区间都不为空,此时我们都需要继续搜索。 也就是说终止搜索条件应该为 left <= right。

      举个例子容易明白一点。 比如对于区间 [4,4],其包含了一个元素 4,因此搜索区间不为空,需要继续搜索(试想 4 恰好是我们要找的 target,如果不继续搜索, 会错过正确答案)。而当搜索区间为 [left, right) 的时候,同样对于 [4,4),这个时候搜索区间却是空的,因为这样的一个区间不存在任何数字·。

1.2.1 左闭右闭

  • 代码实现
int binarySearch(vector<int>& nums,int target){//采用左闭右闭区间int left = 0;int right = nums.size()-1;while(left <= right){int mid = left + (right - left) / 2;if(nums[mid] > tagert)right = mid - 1;else if(nums[mid] < target)left = mid + 1;else return mid;}//左闭右闭区间结束,left=right+1 //此时,没有target,返回-1return -1;
}

1.2.2 左闭右开

  • 代码实现
int binarySearch(vector<int>& nums,int target){//采用左闭右开区间int left = 0;int right = num.size();while(left < right){//此处不同int mid = left + (right - left) / 2;if(nums[mid] < target)left = mid + 1;else if(nums[mid > target])rigth = mid;//此处不同else return mid;}return -1;
}

1.3 寻找最左满足条件的边界

  • 说明

    • 应该插入的位置,使得插入之后列表仍然有序;
    • 另外如果有多个满足条件的值,我们返回最左侧的。 比如一个数组 nums: [1,2,2,2,3,4],target 是 2,我们应该插入的位置是 1
  • 寻找最左,用右边逼近最左边

1.3.1 左闭右闭

  • 代码实现
int leftBound(vector<int>& nums,int target){//采用左闭右闭区间 --- 精简 --- 合并相等情况int left = 0;int right = nums.size()-1;while(left <= right){int mid = left + ((right - left) >> 1);if(nums[mid] >= target)right = mid - 1;else left = mid + 1;}//结束时,left == right + 1,[right,right+1(left)],需要检查是否越界//left<=right,最大就是right + 1 = nums.size()if(left == num.size() || nums[left] != target)return -1;return left;
}

1.3.2 左闭右开

  • 代码实现
int leftBound(vector<int>& nums,int target){//采用左闭右开区间 --- 精简 --- 合并相等情况int left = 0;int right = nums.size();while(left < right){int mid = left + (right - left) / 2;if(nums[mid] >= target)right = mid;else left = mid + 1;}//结束时,[left,right],left == right//target很大,left一直右移if(left == nums.size() || nums[left] != target)return -1;return left;
}

1.4 寻找最右满足条件的边界

1.4.1 左闭右闭

  • 代码实现
int rightBound(vector<int>& nums,int target){//采用左闭右闭区间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 - 1;}//结束时,[right, left],left == right+1;//1、分析返回值,return left - 1 / right;//2、分析越界情况,left->[0,nums.size()],left -1 ->[-1,nums.size()-1]if(left - 1 < 0 || nums[left - 1] != target)return -1;return left - 1;//return right;
}

1.4.2 左闭右开

  • 代码实现
int rightBound(vector<int>& nums,int target){//采用左闭右开区间int left = 0;int right = nums.size();while(left < right){int mid = left + (right - left) / 2;if(nums[mid] <= target)left = mid + 1;else right = mid;}if(left - 1 < 0 || nums[left - 1] != target)return -1;//结束时,[left,right]left == right,return left - 1;//return right - 1;
}
  • 为什么返回left/right-1?

  • 最后的判断处理

  • 小结:
  • 1、判断返回值,通过nums[mid] == target情况判断,分析left/right与mid的关系;
  • 2、判断越界,分析left,right的取值范围;

1.5 寻找最左插入位置

  • 找不到不应该返回-1,而是返回应该插入的位置;

1.5.1 左闭右闭

  • 代码实现
void leftInsert(vector<int>& nums,int target){//采用左闭右闭区间,右边逼近左边int left = 0;int right = nums.size() - 1;while(left <= right){int mid = left + (right - left) / 2;if(nums[mid] >= target)right = mid - 1;else left = mid + 1;}//结束:[right,left(right + 1)],left = right + 1//mid = right + 1 = left//范围:left->[0,nums.size()],不需要进行区间,相等检查return left;//return right + 1;
}

1.5.2 左闭右开

  • 代码实现
void leftInsert(vector<int>& nums,int target){//采用左闭右开区间,右边逼近左边int left = 0;int right = nums.size();while(left < right){int mid = left + (right -left) / 2;if(nums[mid] >= target)right = mid;else left = mid + 1;}//结束,right = left,[left,right],//mid = right;left->[0,nums.size()]return left;//return right;
}

1.6 寻找最右插入位置

1.6.1 左闭右闭区间

  • 代码实现
void rightInsert(vector<int>& nums,int target){//采用左闭右闭,左边逼近右边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 - 1;}//结束,[right,left(right + 1)],left = right + 1;//mid = left - 1 = right;left->[0,nums.size()],//left-1 -> [-1,nums.size()-1],注意,是寻找右边插入位置,因此+1    return left;//return right + 1
}

1.6.2 左闭右开区间

  • 代码实现
void rightInsert(vector<int>& nums,int target){//采用左闭右开区间,左边逼近右边int left = 0;int right = nums.size();while(left < right){int mid = left + (right - left) / 2;if(nums[mid] <= target)left = mid + 1;else right = mid;}//结束,[left,right],left == right, mid = left - 1;//left->[0,nums.size()]return left;//return right;
}

【二分法】多种情况下的边界条件,区间选择汇总,小结相关推荐

  1. 【算法】二分法多种情况详解

    二分法多种情况详解 1.存在的问题 2.[left, right] 左闭右闭区间 a. 注意: b. 代码实现: c. 代码优化: d.示例: 69. x 的平方根 3. [left, right) ...

  2. Java实现多种情况下语言本地化

    Android 多种情况下语言本地化 Android中的本地化又叫国际化主要设计一种适应于多种语言的程序过程.下面我们来了解一下两种不同情况下 的本地化.  一.程序中实现本地化 首先介绍一下文件命名 ...

  3. java在gc正常工作的情况下_最新JVM面试题小结,程序猿直呼内行

    这篇文章主要介绍了JVM面试题小结(2020最新版),觉得挺不错的,现在分享给大家,也给大家做个参考. Java内存区域 说一下 JVM 的主要组成部分及其作用? JVM包含两个子系统和两个组件,两个 ...

  4. 博图SCL编程——多种情况下的开关阀控制

    博图Tia Portal学习教程目录 设备介绍 我们以普通电动开关阀为例,一般至少会有开启.关闭.开启到位反馈.关闭到位反馈4个信号,如下图. 也有一些会更加丰富一点,例如这款西门子的电动风阀执行器, ...

  5. 博图——多种情况下的开关阀控制

    设备介绍 我们以普通电动开关阀为例,一般至少会有开启.关闭.开启到位反馈.关闭到位反馈4个信号,如下图. 也有一些会更加丰富一点,例如这款西门子的电动风阀执行器,除了正常的正反转和开/关到位信号,还有 ...

  6. 多网络情况下,Kafka客户端如何选择合适的网络发起请求

    作者:石臻臻, CSDN博客之星Top5.Kafka Contributor .nacos Contributor.华为云 MVP ,腾讯云TVP, 滴滴Kafka技术专家 . LogiKM PMC( ...

  7. 在生意不好做的情况下, 你会选择坚持,还是去重新找一个新行业?

    之前一天外卖,卖200多,现在少说也有2k多了 为啥转店?昨天我去他店里跟他做了认真的沟通 才了解到店里的房租很贵,一年10w➕ 转让费也有15w,一天店里没啥生意 主要靠外卖, 最近周边的两个大学都 ...

  8. 我可以在不提供FTP访问的情况下安装/更新WordPress插件吗?

    我在实时服务器上使用WordPress ,该服务器仅通过SSH密钥使用SFTP . 我想安装和升级插件,但是看来您需要输入FTP登录才能安装插件. 有没有一种方法可以通过手动上传文件而不是让WordP ...

  9. Linux下Laravel访问MSSQL的方式小结

    安装驱动让PHP可访问MSSQL PHP访问MSSQL的两个方案 FreeTDS+DBLIB UnixODBC+SQLSRV Laravel 访问MSSQL 问题1:同时安装了两套方案的情况下,Lar ...

最新文章

  1. SAP MM 如何看一个采购申请是由APO系统创建后同步过来的?
  2. python 在内网windows环境下pip三方包
  3. 一行代码求两个数的最大公约数
  4. vue后端框架mysql_springboot + vue 前后端结合·数据库查询
  5. oracle命令未正确结束_详解Oracle数据库终止正在进行expdp导出数据的正确操作
  6. 卷积神经网络(Convolutional Neural Networks,CNNS/ConvNets)
  7. 19 删除链表的倒数第N个
  8. C—蓝彗星(差分问题)
  9. 设置linux环境变量
  10. Spring @AutoWired实现原理
  11. CentOS6.7安装Python3.4
  12. 【语音隐写】基于matlab小波变换算法求解水印嵌入提取【含Matlab源码 513期】
  13. 熊猫烧香源码分析_学习大熊猫分析
  14. android EditText的美化
  15. 云计算与虚拟化技术发展编年史
  16. 微信小程序内嵌网页链接
  17. PCB设计规则总结和原因分析
  18. 记一次-更新win10版本到2004
  19. morlet包络检波matlab,包络检波技术,envelope detection technique,音标,读音,翻译,英文例句,英语词典...
  20. vue中的project和inject

热门文章

  1. 第一期 前言 《路由器就是开发板》
  2. mysql——查询优化案例计算
  3. suricata中的单模匹配和多模匹配
  4. 树莓派连接yl-69土壤湿度传感器
  5. Visual Studio 2022 正式版下载教程
  6. 什么是哈希?哈希的模拟实现
  7. 什么是 Web 服务器(server)
  8. 寻找最大公约数c语言,C语言程序设计100例之(10):最大公约数
  9. 2022.03.23绝世武功
  10. 前端入门——JavaScript