二分法查找平方和_面试手撕系列:二分法
O(logn)
。
感觉很抽象的样子 举一个简单通俗易懂的例子你不知道自己长得怎么样,然后去找了10个人 ,评分分别为1-10分首先把5号拉出来,让大家看看是不是这个人和你比哪个优秀如果你比五号选手长得帅,那么你就不用和1-4号比了,这个区间就缩短成[5-10]如果不幸的比五号选手长得丑,那么这个区间就缩短成了[1-4]这里介绍两个二分法的模板 主要区别在于当前数是被划分到左区间
还是右区间
模板
boolcheck(int x) {/* ... */} // 检查x是否满足某种性质// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:intbsearch_1(int l, int r){while (l {int mid = l + r >> 1;if (check(mid)) r = mid; // check()判断mid是否满足性质else l = mid + 1; }return l;}// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:intbsearch_2(int l, int r){while (l {int mid = l + r + 1 >> 1;if (check(mid)) l = mid;else r = mid - 1; }return l;}
二分法作为一种搜索上快速的算法,可以把复杂度从O(N)
变成O(log N)
,要满足二分法搜索的条件是搜索区间内满足单调性为什么会有两个模板呢可以看到在区分id的时候可以分为mid=(l+r)/2
和(l+r)/2+1
与此同时 带来了当前数字索引划分区间的不同话不多说先来两个题目试一试水69 X的平方根
实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:输入: 4输出: 2
示例 2:输入: 8输出: 2说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
这个题目使用二分法还是比较明显的使用二分法搜索平方根的思想很简单,就类似于小时候我们看的电视节目中的“猜价格”游戏,高了就往低了猜,低了就往高了猜,范围越来越小。因此,使用二分法猜算术平方根就很自然。存在三种情况:
平方小于目标数 往高走
平方大于目标数 往低走
平方和恰好等于目标数 跳出循环
//采用二分模板 mid划到了左区间long left=1;long right=x;while(left long mid=(left+right)/2+1;if(mid*mid>x)//平方大于目标数 往低走 right=mid-1;else if(mid*mid//平方大于目标数 往低走 left=mid;else {//平方和恰好等于目标数 跳出循环 left=mid;break; } }return (int)(left);
74 搜索二维矩阵
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:每行中的整数从左到右按升序排列。每行的第一个整数大于前一行的最后一个整数。
输入:matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50]]target = 3输出: true
输入:matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50]]target = 13输出: false
这个题目也可以采用二分 先找一下规律发现 每行的第一个整数大于前一行的最后一个整数 所以这个数组 从上到下 从左到右是依次递增的 所以我们可以采用两次二分法第一次二分的目的是锁定这个数在哪一行上
int left=0;int right=Hang-1;while(left<right){int mid=(left+right)/2+1;if(matrix[mid][0]>target)//当前这个行首元素大于target 说明不可能在这一行 right=mid-1; else if(matrix[mid][0]<=target)//小于或者等于的时候 说明可能是在这一行上left=mid; }//最后这个left就是具体哪一行
第二次二分的目的是锁定这个数在这一行的哪一列上主要判断索引为(Hang,mid)这个元素与target的关系
Hang = left;left =0;right=Lie-1;while(left int mid=(left+right)/2+1;if(matrix[Hang][mid]>target)//如果这一行上坐标为(Hang,mid)的元素大于target 说明目标数可能在左边 right=mid-1;else if(matrix[Hang][mid]//如果这一行上坐标为(Hang,mid)的元素小于target 说明目标数可能在右边 left=mid;else //相等的话就是Truereturn true;}//最后找到这个数但是不一定是和目标数相等 要判断一下if(matrix[Hang][left]==target)return true;else return false;
查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。
输入: nums = [5,7,7,8,8,10], target = 8输出: [3,4]
输入: nums = [5,7,7,8,8,10], target = 6输出: [-1,-1]
因为数组已经排过序了,我们可以使用二分查找的方法去定位左右下标。1,使用二分法判断是否存在目标值2,使用二分法找到第一个 大于等于 target 的位置i3,使用二分法找到最后一个 小于等于 target的位置j这个过程类似什么 类似我们高中学过的夹逼准则吧
由于数组有序且从小到大排序 那么找到的[i,j]区间里必定是目标区间 当然还得判断目标区间是否存在使用二分法找到第一个 大于等于 target 的位置i
int left=0;int right=nums.length-1;while(left<right){int mid=(left+right)/2+1;if(nums[mid]<=target)left=mid;else right=mid-1; }
使用二分法找到最后一个 小于等于 target 的位置j
left=0;right=nums.length-1;while(left<right){int mid=(left+right)/2;if(nums[mid]>=target)right=mid;elseleft=mid+1;}
最后验证区间是否符合我们的要求即可287 寻找重复数
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
输入: [1,3,4,2,2]输出: 2
输入: [3,1,3,4,2]输出: 3
说明:
不能更改原数组(假设数组是只读的)。
只能使用额外的 O(1) 的空间。
时间复杂度小于 O(n^2) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。
这个题目看上去可以用暴力的做法去做,但是暴力做法的复杂度是在O(n^2),肯定是不行的既然要小于O(n^2) 灵机一动 要不我先排个序
且慢 这题排序好像帮助也不大 上头了上头了抽根烟冷静一下
n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n)那就可以保证至少有一个数是重复的慢着 这不就是抽屉原理嘛所谓抽屉原理就是n+1个苹果 放到n个抽屉里 肯定有一个抽屉是放了两个苹果以上 而且题目中说只有一个抽屉是放了两个苹果 其他抽屉放了一个苹果好了我先生成一个抽屉 把苹果放进去不就好了且慢 这个题不能使用额外空间我们回到刚开始的暴力做法 暴力做法是指从1遍历到n看看1-n上哪个数是出现两次的假设这个重复出现的数是x+1 那么1-x 出现的次数就是x1-(x+1)出现的次数就是x+2好像可以看到二分的性质了二分的依据就是 1-x 出现的次数是不是x
如果是 那么就说明1-x上每个数都只出现了一次 目标数还得往大找
如果不是 那么说明1-x上有一个数是出现了两次 目标数得往小了找
那么我们要找出这个引起质变的数即可
int n=nums.length;int l=0;int r=n-1;while(l int mid=(l+r)/2;int cnt=0;for(int i=0;i//计算1-mid 上每个数出现的次数if(nums[i]<=mid) cnt+=1; }if(cnt<=mid)//如果是每个数都出现了一次 那么往大找 l=mid+1;else//否则往小找 r=mid;}return l;
162 寻找峰值
峰值元素是指其值大于左右相邻值的元素。给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。你可以假设 nums[-1] = nums[n] = -∞。
例 1:输入: nums = [1,2,3,1]输出: 2解释: 3 是峰值元素,你的函数应该返回其索引 2。
示例 2:输入: nums = [1,2,1,3,5,6,4]输出: 1 或 5解释: 你的函数可以返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。
说明:
你的解法应该是 O(logN) 时间复杂度的。
这个题目算是二分法里相对抽象的模型了 O(logN) 也在提示你往二分方面想不过还好题目给了点提示 nums[-1] = nums[n] = -∞由于峰值元素是指其值大于左右相邻值的元素我们可以把这个数组的最左端和最右端看作是负无穷那么只要是任意一个实数 他小于两边的元素 或者大于两边的元素 他就是峰值举个例子数组[1] 它的峰值就是1 因为 nums[-1] = nums[n] = -∞
数组[1,2] 它的峰值就是2 因为1<2< -∞给大家画一个山峰可以知道山峰的确定和他的绝对高度 无关 和他的相对高度有关只要他是比它的邻居都高 那它就是山峰
抽象成二分法怎么理解 如这个图所示 我就比较nums[mid]和nums[mid+1]之间的关系无非就是只有两个情况
nums[mid] 也就是右边的元素大于左边的 那从左往右看就是上坡 上坡路必定存在一个顶峰
nums[mid]>nums[mid+1] 也就是右边的元素小于等于左边的 那从右往左看就是一个平滑的下坡,那这个顶峰必定是在mid这个位置之前,不然我也不可能有下坡的空间
所以抽象成二分模型就是
int l=0;int r=nums.length-1;while(l int mid=(l+r)/2;if(nums[mid]1])//如果上坡 继续往前走 看看顶峰在哪里 l=mid+1;else//如果下坡了 往回走 直到找到顶峰 r=mid;}return l;
最后推荐几道题目,也是使用二分的,相信你看到这里也对二分有了更高的认识,不再是有序才可以用二分
Leetcode-278 第一个错误的版本Leetcode-275 H指数IILeetcode-35 搜索插入位置Leetcode-53 寻找旋转排序数组中的最小值
往期精彩回顾
三月算法岗面经
阿里笔试题两道
扫码关注我,加入每日一题算法交流群/秋招备战群吧请备注 学校+昵称才可以加群噢
二分法查找平方和_面试手撕系列:二分法相关推荐
- 2023华为OD面试手撕代码经验分享
我们先来看下这个同学的面试经历吧,非常有借鉴的意义. [22届考研渣渣的od求职之旅,推荐一下两个人,德科hr和牛客的老哥] "*********",hr给了机会吧,一开始我都没想 ...
- 详解面试手撕过的那些排序算法
前言 只要去大厂面试,必定有一轮算法面试,而这一轮往往是阻碍程序员面试成功的关键.一个程序员的算法基本功是否扎实能够体现出自身的开发能力,下面我尽可能的把常用的排序算法讲清楚. 排序简介 排序(Sor ...
- 蛇形打印数组(某宝典公司面试手撕代码题)
背景杂谈 不知道为什么,可能脑袋一下放空了,一不小心就想到了大约2年前,在某个知名的宝典公司面试中,遇到了一道手撕代码题,和多年前的google的那道螺旋遍历数据有异曲同工之妙.现脑洞大开,想写下与大 ...
- 前端date format_前端面试-手撕代码篇
前言 在前端面试有一个非常重要的环节,也是面试者最担心的一个环节.对"手撕代码"的考察需要面试者平时总结和积累(临时抱佛脚是不好使的),在这里笔者就自己如何攻破"手撕代码 ...
- FPGA秋招面试手撕代码20+
目录 前言 1.序列检测器 (1)三段式状态机实现方式 (2)移位寄存器实现方式 2.序列生成器 (1)移位寄存器方式实现 (2)计数器方式实现 (3)三段式状态机方式实现 3.分频 (1)偶数分频 ...
- 手撕系列-AdaBoost
简介: 上次我们介绍过Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器). 本次将通过一个简单示 ...
- C/C++笔试面试手撕代码注意事项
C/C++笔试和面试过程中难免会要手撕代码,那么手撕代码,面试官或者看试卷的人一般会看哪些点呢?我列举了一些我认为的点(码农适用): 算法思想是否正确 代码逻辑是否清晰明了 代码风格是否美观简洁 注释 ...
- 2023华为OD面试手撕代码真题
很多小伙伴后台私信我,让我出一些面试中的手撕代码题. 一般面试的时候每一轮技术面都会出一到两个手撕代码题,这些题的特点就是,非常短小,易于理解.不可能会再出阅读理解一样的机试题的.但是这些题目也非常注 ...
- 剁馅机器人图片_黄金手撕面包培训图片信得过的工艺利润高
使得和好的面团放气分割成一样的等份.使将用料的母鸡蛋拌之成为全蛋液,咖喱包挨次尤为均匀沾裹上生面粉全蛋液面包面高筋面粉. 使将脆酥面之皮柿子胡萝卜各自切成条丁,打开火点燃添加饮用水,使将胡萝卜丢入过一 ...
最新文章
- vue组件定义、组件的切换、组件的通信、渲染组件的几种方式(标签、路由、render)...
- SigmaPlot 12.0 中文版 for Win 专业的科研绘图下载及教材
- 我们无法在你选择的位置安装Windows。0x80300002
- boost::range_category和boost::iterator_category相关的测试程序
- ubuntu中的Jupyter Notebook更换浏览器需要输入密码
- 时间序列 线性回归 区别_时间序列分析的完整介绍(带R)::线性过程I
- GitHub Universe 2021|MS Reactor 邀你共聚年度盛会
- linux总线错误无法删除文件,linux – 系统D-Bus不允许使用conf文件来破坏所有权...
- 苹果重奖库克,挽留其留任到2025年,网友:雷军又没机会了
- php xml视频教程,传智播客PHP2015-XML视频教程
- win10无线投屏_Win10电脑屏幕分割成四分屏投屏测试
- Android ThreadPool
- 使用TF卡烧录Jetson NX开发板
- cmd命令根据wsdl文件生成Java文件
- 卸载网易邮箱大师邮件从服务器删除,如何卸载网易邮箱大师 网易邮箱大师卸载教程...
- 使用JavaScript获取设备屏幕的宽度
- stellarium-0.19.3.1-win64.exe下载
- 涉密计算机怎么更新补丁,windows系统补丁你更新还是不更新?
- 读于博士SI设计手记有感
- 你真的了解重排和重绘吗?
热门文章
- 如何隐藏SAP CRM WebClient UI配置页面的字段
- SAP Fiori Elements的change and save实现原理
- UI Component in CRM WebUI and Hybris
- 微软的ppt现在可以直接导出成可以播放的mp4了,非常方便
- CRM Fiori Opportunity应用的新建Opportunity操作的实现
- SCN exercise navigation的实现原理
- SAP UI5 ComponentBase createMetaData signature - why is MD hard coded
- SAP UI5 click list item to navigate to detail page
- jMeter 线程启动时间
- language dropdown list - filter logic