【二分查找】力扣69:x 的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

依题意,结果向下取整。

  1. 二分查找
    由于 x 平方根的整数部分 ans 是满足 k ^ 2 ≤ x 的最大 k 值,因此我们可以对 k 进行二分查找,从而得到答案。
    二分查找的下界为 0,上界可以粗略地设定为 x。在二分查找的每一步中,我们只需要比较中间元素 mid 的平方与 x 的大小关系,并通过比较的结果调整上下界的范围。
    1.1 二分法模板
class Solution:
    def mySqrt(self, x: int) -> int:
        left = 0
        right = x
        while left <= right:
            mid = (left + right) // 2
            if mid * mid == x:
                return mid
            elif mid * mid < x:
                left = mid + 1
            else:
                right = mid - 1
        return right # 向下取整为right

1.2 二分法模板的特殊处理

class Solution:
    def mySqrt(self, x: int) -> int:
        left = 0
        right = x
        ans = -1
        while left <= right:
            mid = (left + right) // 2
            if mid * mid <= x:
                ans = mid # 只用左侧的值作为结果,因为是要求结果向下取整
                left = mid + 1
            else:
                right = mid - 1
        return ans

时间复杂度:O(logx),即为二分查找需要的次数。
空间复杂度:O(1)。

我写了一个套路,助你随心所欲运用二分搜索

  1. 袖珍计算器算法
    「袖珍计算器算法」是一种用指数函数 exp 和对数函数 ln 代替平方根函数的方法。我们通过有限的可以使用的数学函数,得到我们想要计算的结果。
    我们将 \sqrt{x} 写成幂的形式 x^{1/2},再使用自然对数 e 进行换底,得到image
    这样我们就可以得到 \sqrt{x} 的值了。
    注意:由于计算机无法存储浮点数的精确值(浮点数的存储方法可以参考 IEEE 754,这里不再赘述),而指数函数和对数函数的参数和返回值均为浮点数,因此运算过程中会存在误差。
    因此在得到结果的整数部分 ans 后,我们应当找出 ans 与 ans+1 中哪一个是真正的答案。
class Solution:
    def mySqrt(self, x: int) -> int:
        if x == 0:
            return 0
        ans = int(math.exp(0.5 * math.log(x)))
        return ans + 1 if (ans + 1) ** 2 <= x else ans

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-leetcode-solution/

时间复杂度:O(1),由于内置的 exp 函数与 log 函数一般都很快,我们在这里将其复杂度视为 O(1)。
空间复杂度:O(1)。

  1. 牛顿迭代法

  2. 机器学习 - 梯度下降法
    由于题目设置这里的x是我们常说的y,t是我们常用的x

class Solution:
    def mySqrt(self, x: int) -> int:
        t = 1
        lr = 0.0001 #learning_rate 学习率
        #是用mse均方差损失函数
        #定义精度
        while (x-t**2)**2>0.01:
            # tn = tn-1+损失函数对x求偏导
            t = t-lr*(4*t*(t*t-x)) 
            #损失函数对t求偏导x是常数
            # (x-t^2)^2 对t求导 外导乘内导 
        return int(t)+1 if (int(t)+1)**2<=x else int(t)
        # 注意边界,比如4通过梯度下降以后得到的值是1.97,,,但是我们要返回2 而8通过梯度下降之后是2.8,,但是我们要返回2
        # 所以我们看我们向下取整之后的值 平方后是否可以小于等于x如果可以就返回这个 不行就返回向下取整的值

作者:sunyingjian
链接:https://leetcode-cn.com/problems/sqrtx/solution/python3-ji-qi-xue-xi-ti-du-xia-jiang-fa-iuasz/
posted @   Vonos  阅读(158)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示