当前位置: 首页 > news >正文

二分查找题目:x 的平方根

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 预备知识
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:x 的平方根

出处:69. x 的平方根

难度

3 级

题目描述

要求

给定一个非负整数 x \texttt{x} x,计算并返回 x \texttt{x} x 的算术平方根。

由于返回类型是整数,因此小数部分被舍去,只返回结果的整数部分

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) \texttt{pow(x, 0.5)} pow(x, 0.5) 或者 x ** 0.5 \texttt{x ** 0.5} x ** 0.5

示例

示例 1:

输入: x = 4 \texttt{x = 4} x = 4
输出: 2 \texttt{2} 2

示例 2:

输入: x = 8 \texttt{x = 8} x = 8
输出: 2 \texttt{2} 2
解释: 8 \texttt{8} 8 的算术平方根是 2.82842... \texttt{2.82842...} 2.82842...,由于小数部分被舍去,因此返回 2 \texttt{2} 2

数据范围

  • 0 ≤ x ≤ 2 31 − 1 \texttt{0} \le \texttt{x} \le \texttt{2}^\texttt{31} - \texttt{1} 0x2311

解法一

思路和算法

r r r 表示 x x x 的算术平方根的整数部分,则 r r r 是非负整数。

x = 0 x = 0 x=0 时, r = 0 r = 0 r=0。当 x > 0 x > 0 x>0 时,对于任意非负整数 y y y,当 y ≤ r y \le r yr y 2 ≤ x y^2 \le x y2x,当 y > r y > r y>r y 2 > x y^2 > x y2>x。因此可以使用二分查找得到 r r r

由于 r r r 一定在范围 [ 0 , x ] [0, x] [0,x] 内,因此初始时二分查找的范围的下界和上界是 low = 0 \textit{low} = 0 low=0 high = x \textit{high} = x high=x

每次查找时,取 mid \textit{mid} mid low \textit{low} low high \textit{high} high 的平均数向上取整,比较 mid 2 \textit{mid}^2 mid2 x x x 的大小关系,调整二分查找的范围。

  • 如果 mid 2 ≤ x \textit{mid}^2 \le x mid2x,则 r r r 大于等于 mid \textit{mid} mid,因此在范围 [ mid , high ] [\textit{mid}, \textit{high}] [mid,high] 中继续查找。

  • 如果 mid 2 > x \textit{mid}^2 > x mid2>x,则 r r r 小于 mid \textit{mid} mid,因此在范围 [ low , mid − 1 ] [\textit{low}, \textit{mid} - 1] [low,mid1] 中继续查找。

low = high \textit{low} = \textit{high} low=high 时,结束查找,此时 low \textit{low} low 即为 r r r,返回 low \textit{low} low

实现方面需要注意处理溢出的情况。

二分查找的过程中,每次取 mid = ⌈ low + high 2 ⌉ \textit{mid} = \Big\lceil \dfrac{\textit{low} + \textit{high}}{2} \Big\rceil mid=2low+high,等价于 mid = low + ⌊ high − low + 1 2 ⌋ \textit{mid} = \textit{low} + \Big\lfloor \dfrac{\textit{high} - \textit{low} + 1}{2} \Big\rfloor mid=low+2highlow+1。由于 x x x 的取值范围是 [ 0 , 2 31 − 1 ] [0, 2^{31} - 1] [0,2311],因此 high \textit{high} high 的最大值可能是 2 31 − 1 2^{31} - 1 2311。当 low = 0 \textit{low} = 0 low=0 high = 2 31 − 1 \textit{high} = 2^{31} - 1 high=2311 时, high − low + 1 = 2 31 \textit{high} - \textit{low} + 1 = 2^{31} highlow+1=231,超出了 32 32 32 位整型的表示范围,会导致溢出。

为了避免溢出,一种做法是将 low \textit{low} low high \textit{high} high mid \textit{mid} mid 都声明成 64 64 64 位整型,另一种做法是对 x = 0 x = 0 x=0 的情况特判。具体做法是,当 x = 0 x = 0 x=0 时返回 0 0 0,当 x > 0 x > 0 x>0 x x x 的算术平方根一定大于等于 1 1 1,因此二分查找的范围的下界和上界初始化为 low = 1 \textit{low} = 1 low=1 high = x \textit{high} = x high=x,可以避免溢出。

代码

class Solution {public int mySqrt(int x) {if (x == 0) {return 0;}int low = 1, high = x;while (low < high) {int mid = low + (high - low + 1) / 2;if ((long) mid * mid <= x) {low = mid;} else {high = mid - 1;}}return low;}
}

复杂度分析

  • 时间复杂度: O ( log ⁡ x ) O(\log x) O(logx)。二分查找的次数是 O ( log ⁡ x ) O(\log x) O(logx),每次查找的时间是 O ( 1 ) O(1) O(1),时间复杂度是 O ( log ⁡ x ) O(\log x) O(logx)

  • 空间复杂度: O ( 1 ) O(1) O(1)

解法二

预备知识

该解法使用牛顿迭代法计算给定非负整数的算术平方根。牛顿迭代法(Newton’s method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),是牛顿提出的一种在实数域和复数域上近似求解方程的方法。

牛顿迭代法的本质是使用泰勒级数,从初始近似值开始快速向函数的零点逼近。其原理如下。

假设函数 f ( x ) f(x) f(x) 的零点是 r r r,则 r r r 是方程 f ( x ) = 0 f(x) = 0 f(x)=0 的根。选取 x 0 x_0 x0 作为 r r r 的初始近似值,则 ( x 0 , f ( x 0 ) ) (x_0, f(x_0)) (x0,f(x0)) 是函数 y = f ( x ) y = f(x) y=f(x) 的图像上的一点,过该点作函数图像的切线,切线方程是 y − f ( x 0 ) = f ′ ( x 0 ) ( x − x 0 ) y - f(x_0) = f'(x_0)(x - x_0) yf(x0)=f(x0)(xx0),切线与 x x x 轴交点的横坐标是 x 1 = x 0 − f ( x 0 ) f ′ ( x 0 ) x_1 = x_0 - \dfrac{f(x_0)}{f'(x_0)} x1=x0f(x0)f(x0) x 1 x_1 x1 称为 r r r 的一次近似值。使用相同的方法,从 x 1 x_1 x1 计算得到 x 2 = x 1 − f ( x 1 ) f ′ ( x 1 ) x_2 = x_1 - \dfrac{f(x_1)}{f'(x_1)} x2=x1f(x1)f(x1) x 2 x_2 x2 称为 r r r 的二次近似值。推广到一般情形,当 k > 0 k > 0 k>0 时, x k = x k − 1 − f ( x k − 1 ) f ′ ( x k − 1 ) x_k = x_{k - 1} - \dfrac{f(x_{k - 1})}{f'(x_{k - 1})} xk=xk1f(xk1)f(xk1) x k x_k xk 称为 r r r k k k 次近似值,上述公式称为牛顿迭代公式。

如果函数的零点存在,则近似值会向零点收敛。当迭代次数达到预设的上限,或者相邻两次近似值足够接近时,即可结束迭代过程。

思路和算法

计算 x x x 的算术平方根,等价于计算函数 f ( t ) = t 2 − x ( t ≥ 0 ) f(t) = t^2 - x (t \ge 0) f(t)=t2x(t0) 的零点。该函数的导函数为 f ′ ( t ) = 2 t f'(t) = 2t f(t)=2t,牛顿迭代公式为 t k = 1 2 ( t k − 1 + x t k − 1 ) t_k = \dfrac{1}{2}\Big( t_{k - 1} + \dfrac{x}{t_{k - 1}} \Big) tk=21(tk1+tk1x)

x x x 作为零点的初始近似值,由于当 x x x 未到达零点时, x x x 大于 x \sqrt{x} x ,因此每次迭代时都会将 t k t_k tk 减小,可以到达 x \sqrt{x} x 处的零点。

牛顿迭代公式中,自变量 t t t 出现在分母上。当 x = 0 x = 0 x=0 时, t t t 的初始近似值 t 0 = 0 t_0 = 0 t0=0,此时会出现被零除的情况。为了避免出现被零除的情况,应确保 t > 0 t > 0 t>0,因此当 x = 0 x = 0 x=0 时返回 0 0 0,当 x > 0 x > 0 x>0 时使用牛顿迭代法计算 x x x 的算术平方根。

代码

class Solution {static final double EPSILON = 1e-6;public int mySqrt(int x) {if (x == 0) {return 0;}boolean flag = true;double sqrt = x;while (flag) {double curr = (sqrt + x / sqrt) / 2;if (Math.abs(curr - sqrt) < EPSILON) {flag = false;} else {sqrt = curr;}}return (int) sqrt;}
}

复杂度分析

  • 时间复杂度: O ( log ⁡ x ) O(\log x) O(logx)。牛顿迭代法计算算术平方根的时间复杂度是 O ( log ⁡ x ) O(\log x) O(logx)

  • 空间复杂度: O ( 1 ) O(1) O(1)


http://www.mrgr.cn/news/70418.html

相关文章:

  • 力扣 LeetCode 206. 反转链表(Day2:链表)
  • 数学建模模型算法-Python实现
  • 明源地产ERP系统 WFWebService 反序列化漏洞复现
  • 量化交易系统开发-实时行情自动化交易-3.4.2.2.Okex交易数据
  • linux基础-完结(详讲补充)
  • 241111.学习日志——[CSDIY] Cpp零基础速成 [00]
  • [分享]分享一下我用了十几年的按键扫描方法
  • 北京大学、华为公司联合发布《中国城市治理数字化转型报告(2024)》49页PDF附下载
  • 谷歌Linux内核自动测试平台架构介绍-用自动测试测试难以测试的问题
  • 【RabbitMQ】06-消费者的可靠性
  • 【前端】手写一个简单的分页器
  • 如何解决亚马逊商家IP问题:静态住宅IP的优势与选择指南
  • 1547. 切棍子的最小成本-cangjie
  • 网络、子网
  • 实验室信息管理系统源码,医院LIS系统源码,C/S结构,C#语言开发,适合上项目。
  • vxe-vxe-colgroup后端返回数据 对数据进行处理 动态合并分组表头(v-if控制表格渲染(数据请求完成后渲染))
  • ROS2在自定义服务接口中的常数调用(python)
  • c++如何绑定一个类与类内成员的关系
  • AES加密原理
  • Docker使用docker-compose一键部署nacos、Mysql、redis
  • 分段式爬虫和数据采集的有趣话题
  • c++基础30字符
  • 【前端学习笔记】JavaScript学习一【变量与数据类型】
  • 体育数据API纳米篮球数据API:网球数据接口文档API示例③
  • 多态之魂:C++中的优雅与力量
  • 位运算_常见位运算总结