字节笔试题 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)分析下面程序的输出(* 与 -- 运算符优先级问 ...
随机推荐
- ctfhub技能树—sql注入—时间盲注
打开靶机 查看页面信息 测试时间盲注 可以看到在执行命令后会有一定时间的等待,确定为时间盲注 直接上脚本 1 #! /usr/bin/env python 2 # _*_ coding:utf-8 _ ...
- python协程爬取某网站的老赖数据
import re import json import aiohttp import asyncio import time import pymysql from asyncio.locks im ...
- RecyclerView 源码分析(二) —— 缓存机制
在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ...
- mongodb简单运用
mongodb NoSQL(Not Only SQL),意思是"不仅仅是 SQL",指的是非关系型数据库,是对不同于传统的关系型数据库的数据库管理系统的统称. NoSQL 用于超大 ...
- SQLHelper ------ python实现
SQLHelper ------ python实现 1.第一种: import pymysql import threading from DBUtils.PooledDB import Pooled ...
- scrapy异步的爬虫框架简单的使用
scrapy异步的爬虫框架 异步的爬虫框架 高性能的数据解析,持久化存储,全栈数据的爬取,中间件,分布式 框架:就是一个集成好了各种功能且具有很强通用性的一个项目模板. 环境安装: Linux: pi ...
- secrets 管理工具 Vault 的介绍、安装及使用
原文:https://ryan4yin.space/posts/expirence-of-vault/ Vault 是 hashicorp 推出的 secrets 管理.加密即服务与权限管理工具.它的 ...
- windows桌面快速添加控制面板网络等图标
默认安装后的windows系统只有回收站. rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0
- 解决windows git乱码问题
在windows中打开git bash git config --global i18n.commitencoding utf-8 设置提交日志使用utf-8 git config --g ...
- 编写Hello World ts程序
准备工作 预装软件NodeJs和VSCode 新建文件夹ts_in_action npm命令初始化工程:npm init -y,生成package.json文件 全局安装TypeScript:npm ...