更多精彩文章请关注公众号: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 的平方根的更多相关文章

  1. Java实现 LeetCode 69 x的平方根

    69. x 的平方根 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去. 示例 1: 输入: ...

  2. [leetcode] 69. x 的平方根(纯int溢出判断实现)

    69. x 的平方根 非常简单的一个题,用二分法逼近求出ans即可,额外注意下溢出问题. 不过我要给自己增加难度,用long或者BigNum实现没意思,只能使用int类型 换句话当出现溢出时我们自己得 ...

  3. LeetCode 69 x 的平方根

    链接:https://leetcode-cn.com/problems/sqrtx 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数, ...

  4. [LeetCode]69. x 的平方根(数学,二分)

    题目 https://leetcode-cn.com/problems/sqrtx 题解 方法一:牛顿迭代法 按点斜式求出直线方程(即过点Xn,f(Xn)),然后求出直线与x轴交点,即为Xn+1: 求 ...

  5. C/C++ 笔试题

    /////转自http://blog.csdn.net/suxinpingtao51/article/details/8015147#userconsent# 微软亚洲技术中心的面试题!!! 1.进程 ...

  6. 嵌入式Linux C笔试题积累(转)

    http://blog.csdn.net/h_armony/article/details/6764811 1.   嵌入式系统中断服务子程序(ISR) 中断是嵌入式系统中重要的组成部分,这导致了很 ...

  7. C/C++笔试题(很多)

    微软亚洲技术中心的面试题!!! .进程和线程的差别. 线程是指进程内的一个执行单元,也是进程内的可调度实体. 与进程的区别: (1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位 (2 ...

  8. 非常全面的java基础笔试题

    下面是java基础笔试题,当时我去笔试,做了1个小时(80道选择题,后面的简答题就没时间做了),结果很吓人,太挫了,最后被面试官忽悠去培训去了,呵呵.我偷偷把面试题弄了下来,用来学习吧,也希望能对你们 ...

  9. C/C++笔试题(基础题)

    为了便于温故而知新,特于此整理 C/C++ 方面相关面试题.分享,共勉. (备注:各题的重要程度与先后顺序无关.不断更新中......欢迎补充) (1)分析下面程序的输出(* 与 -- 运算符优先级问 ...

随机推荐

  1. ctfhub技能树—sql注入—时间盲注

    打开靶机 查看页面信息 测试时间盲注 可以看到在执行命令后会有一定时间的等待,确定为时间盲注 直接上脚本 1 #! /usr/bin/env python 2 # _*_ coding:utf-8 _ ...

  2. python协程爬取某网站的老赖数据

    import re import json import aiohttp import asyncio import time import pymysql from asyncio.locks im ...

  3. RecyclerView 源码分析(二) —— 缓存机制

    在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ...

  4. mongodb简单运用

    mongodb NoSQL(Not Only SQL),意思是"不仅仅是 SQL",指的是非关系型数据库,是对不同于传统的关系型数据库的数据库管理系统的统称. NoSQL 用于超大 ...

  5. SQLHelper ------ python实现

    SQLHelper ------ python实现 1.第一种: import pymysql import threading from DBUtils.PooledDB import Pooled ...

  6. scrapy异步的爬虫框架简单的使用

    scrapy异步的爬虫框架 异步的爬虫框架 高性能的数据解析,持久化存储,全栈数据的爬取,中间件,分布式 框架:就是一个集成好了各种功能且具有很强通用性的一个项目模板. 环境安装: Linux: pi ...

  7. secrets 管理工具 Vault 的介绍、安装及使用

    原文:https://ryan4yin.space/posts/expirence-of-vault/ Vault 是 hashicorp 推出的 secrets 管理.加密即服务与权限管理工具.它的 ...

  8. windows桌面快速添加控制面板网络等图标

    默认安装后的windows系统只有回收站. rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0

  9. 解决windows git乱码问题

    在windows中打开git bash git config --global i18n.commitencoding utf-8       设置提交日志使用utf-8 git config --g ...

  10. 编写Hello World ts程序

    准备工作 预装软件NodeJs和VSCode 新建文件夹ts_in_action npm命令初始化工程:npm init -y,生成package.json文件 全局安装TypeScript:npm ...