字节笔试题 leetcode 69. x 的平方根
更多精彩文章请关注公众号:TanLiuYi00
题目

解题思路
题目要求非负整数 x 的平方根,相当于求函数 y = √x 中 y 的值。
函数 y = √x 图像如下:

从上图中,可以看出函数是单调递增的,满足二分查找的条件(区间是有序的),所以可以用二分查找去做。
解题步骤
- 比较 mid * mid 跟 x 的大小,相等则直接返回 mid,否则就去以 mid 为分割点的左右区间查找,直到不满足循环循环条件(left == right + 1 或 left == right 究竟是哪一个主要跟循环条件有关,请看后面的分析)就退出。
- 由于非负整数 x(当 x ≠ 0 时) 的平方根一定是落在区间 [1, x/2 + 1],所以左右边界分别取 1 和 x/2 + 1,而不分别取 0 和 x,这样可缩小查找范围。
- 为了防止 mid * mid 太大而发生整型溢出,取 mid 跟 x/mid 比较。
说明
右边界 right 取 x/2 + 1,而不取 x/2,这是因为当 x = 1 时,right 如果取 x/2,由于 x/2 会向下取整使得 x/2 = 0,此时 left = 1 大于 right = 0,以至于直接跳出循环,导致 1 的平方根为 0,这明显是错误的。
Show me the Code
int mySqrt(int x){
int left = 1, right = x / 2 + 1;
// 循环不变量 始终维持在区间 [left, right] 中查找,当 left = right + 1 时,区间为空,查找结束
// 当 left == right 时,区间 [left, right] 依然有效
while (left <= right) {
// 防止溢出
int mid = left + ((right - left) >> 1);
// mid 大于 √x ,在 mid 前半区间 [left, mid - 1] 中查找,不是 [left, mid]
// 是因为会当查找到 target 时,直接返回 mid,所以没必要再考虑 mid
if (mid > x / mid) {
right = mid - 1;
// mid 小于 √x ,在 mid 后半区间 [mid + 1, right] 中查找
} else if (mid < x / mid) {
left = mid + 1;
// mid 等于 √x ,代表查找到 target,则直接返回
} else {
return mid;
}
}
return right;
}
补充说明
如果没有出现 mid == x / mid 的情况,最后到底是 return right 还是 return left?
1、可以通过调试得出;
2、循环结束的条件是 left = right + 1,示例中提示了当 x = 8,其平方根是 2,有点类似于向下取整的意思,所以是 return right 。
进一步补充
可能有些童鞋会问到,上面代码中循环的条件为何是 left <= right 而不是 left < right,其实这两个条件都可以,主要区别在于:
循环结束的条件不一样,前者是 left = right + 1 后者是 left = right,即前者当 left = right + 1 时,查找区间 [left, right] 为空,后者当 left = right 时,查找区间 [left, right) 为空。
定义的右边界取值不一样,前者右边界取值为 x / 2 + 1,后者可为 x / 2 + 2。
这里会提到一个循环不变量的概念:
循环不变量
1. 初始化:它在循环的第一轮迭代开始之前,应该是正确的。
2. 如果在循环的某一次迭代开始之前它是正确的,那么,在下一次迭代开始之前,它也应该保持正确。
3. 当循环结束时,不变式给了我们一个有用的性质,它有助于表明算法是正确的。
所以本题循环的条件可以是 left <= right 也可以是 left < right,关键是查找的过程中需要一直维护查找区间 [left, right] 或 [left, right)。
下面补充一个循环条件为 left < right 的代码。
最后返回的是 right - 1,这是因为:
定义的查找区间是左闭右开[left, right),取不到右边界 right;当 left == right 时,循环退出,由于 right 取不到并且平方根有点向下取整的意味,所以取 right - 1;
通过调试也能得出。
Show me the Code
int mySqrt(int x){
int left = 1, right = x / 2 + 2;
// 循环不变量 始终维持在区间 [left, right) 中查找,当 left = right 时,区间为空,查找结束
while (left < right) {
// 防止溢出
int mid = left + ((right - left) >> 1);
// mid 大于 √x ,在 mid 前半区间 [left, mid) 中查找
if (mid > x / mid) {
right = mid;
// mid 小于 √x ,在 mid 后半区间 [mid + 1, right) 中查找
} else if (mid < x / mid) {
left = mid + 1;
// mid 等于 √x ,代表查找到 target,则直接返回
} else {
return mid;
}
}
return right - 1;
}
更多精彩文章可关注公众号:TanLiuYi00
字节笔试题 leetcode 69. x 的平方根的更多相关文章
- Java实现 LeetCode 69 x的平方根
69. x 的平方根 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去. 示例 1: 输入: ...
- [leetcode] 69. x 的平方根(纯int溢出判断实现)
69. x 的平方根 非常简单的一个题,用二分法逼近求出ans即可,额外注意下溢出问题. 不过我要给自己增加难度,用long或者BigNum实现没意思,只能使用int类型 换句话当出现溢出时我们自己得 ...
- LeetCode 69 x 的平方根
链接:https://leetcode-cn.com/problems/sqrtx 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数, ...
- [LeetCode]69. x 的平方根(数学,二分)
题目 https://leetcode-cn.com/problems/sqrtx 题解 方法一:牛顿迭代法 按点斜式求出直线方程(即过点Xn,f(Xn)),然后求出直线与x轴交点,即为Xn+1: 求 ...
- C/C++ 笔试题
/////转自http://blog.csdn.net/suxinpingtao51/article/details/8015147#userconsent# 微软亚洲技术中心的面试题!!! 1.进程 ...
- 嵌入式Linux C笔试题积累(转)
http://blog.csdn.net/h_armony/article/details/6764811 1. 嵌入式系统中断服务子程序(ISR) 中断是嵌入式系统中重要的组成部分,这导致了很 ...
- C/C++笔试题(很多)
微软亚洲技术中心的面试题!!! .进程和线程的差别. 线程是指进程内的一个执行单元,也是进程内的可调度实体. 与进程的区别: (1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位 (2 ...
- 非常全面的java基础笔试题
下面是java基础笔试题,当时我去笔试,做了1个小时(80道选择题,后面的简答题就没时间做了),结果很吓人,太挫了,最后被面试官忽悠去培训去了,呵呵.我偷偷把面试题弄了下来,用来学习吧,也希望能对你们 ...
- C/C++笔试题(基础题)
为了便于温故而知新,特于此整理 C/C++ 方面相关面试题.分享,共勉. (备注:各题的重要程度与先后顺序无关.不断更新中......欢迎补充) (1)分析下面程序的输出(* 与 -- 运算符优先级问 ...
随机推荐
- 04--Docker数据卷和数据卷容器
.为什么要使用数据卷: Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了.为了能保存数据在docke ...
- 编年史:OI算法总结
目录(按字典序) A --A* D --DFS找环 J --基环树 S --数位动规 --树形动规 T --Tarjan(e-DCC) --Tarjan(LCA) --Tarjan(SCC) --Ta ...
- 彻底解决小程序无法触发SESSION问题
一.首先找到第一次发起网络请求的地址,将服务器返回set-cookie当全局变量存储起来 wx.request({ ...... success: function(res) { console.lo ...
- 01. struts2介绍
struts2优点 与Servlet API 耦合性低.无侵入式设计 提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能 支持多种表现层技术,如:JSP.freeMarker.veloc ...
- 试玩 GOWOG ,初探 OpenAI(使用 NeuroEvolution 神经进化)与 Golang 多人在线游戏开发
GOWOG: 原项目:https://github.com/giongto35/gowog 我调整过的:https://github.com/Kirk-Wang/gowog GOWOG 是一款迷你的, ...
- Linux更改密码报错:密码未通过字典检查 - 过于简单化/系统化
Linux更改密码报错:密码未通过字典检查 - 过于简单化/系统化 方案一:直接忽略 很容易认为这儿是一个错误,其实可以直接忽略,重新输入密码 [root@localhost ~]# passwd 更 ...
- go 语言开发中 GOPATH问题 与 go语言linux 开发环境 教程
https://github.com/rubyhan1314/Golang-100-Days/blob/master/Day01-15(Go%E8%AF%AD%E8%A8%80%E5%9F%BA%E7 ...
- makefile自动生成学习
https://www.cnblogs.com/jrglinux/p/6964169.html 关键是如何写Makefile.am 其他的交给 自动工具完成 添加一个 很好的博客 学习下 https ...
- 【Android初级】教你用两行代码实现“显示/隐藏密码”的效果
Android里面要使用密码的场景是非常多的,支付宝.微信.淘宝以及各大银行APP,都跟用户的密码有关.用户的密码是极为隐私的,用户在输入时不希望密码被别人看到,所以几乎所有需要输入密码的场景下都会把 ...
- Django(中间件)
中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影响到 ...