[Leetcode] 69. x 的平方根

2018-09-15 23:37:30 +08:00
 Acceml

题目

实现 int sqrt(int x) 函数。

计算并返回 x 的平方根,其中 x 是非负整数。

由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

示例 1:

输入: 4
输出: 2

示例 2:

输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 

由于返回类型是整数,小数部分将被舍去。

题解

方法一:二分查找

找到中间的数: mid = start + (end - start) / 2 而且: mid * mid <= x && (mid + 1) * (mid + 1) > x 但是这么写超出了 Integer 的范围了:

class Solution {
    public int mySqrt(int x) {
        if (x == 0) return 0;
        int start = 1, end = x;
        while (start < end) {
            int mid = start + (end - start) / 2;
            if (mid * mid <= x  && (mid + 1) * (mid + 1) > x)// Found the result
                return mid;
            else if (mid > x / mid)// Keep checking the left part
                end = mid;
            else
                start = mid + 1;// Keep checking the right part
        }
        return start;
    }
}

所以改变一下: mid * mid <= x && (mid+1)(mid+1) > x 下面的 code 为 AC 版本:

class Solution {
    public int mySqrt(int x) {
        if (x == 0) return 0;
        int start = 1, end = x;
        while (start < end) {
            int mid = start + (end - start) / 2;
            if (mid <= x / mid && (mid + 1) > x / (mid + 1))// Found the result
                return mid;
            else if (mid > x / mid)// Keep checking the left part
                end = mid;
            else
                start = mid + 1;// Keep checking the right part
        }
        return start;
    }
}

python 版本

class Solution:
    def mySqrt(self, x):
        start, end = 0, x
        while start <= end:
            # 结果都计算为整数
            mid = start + (end - start) // 2
            if mid * mid <= x < (mid + 1) * (mid + 1):
                return mid
            elif x < mid * mid:
                end = mid
            else:
                start = mid + 1

牛顿迭代法

基本思想:把非线性方程线性化,用线性方程的解逐步逼近原方程的解

求某个数(比如 8)的平方根其实就是求解 f(x) = x^2 - 8 = 0 的解

如上图

点(x[k+1], 0)满足该方程 0 = f ( x[k]) + f'(x[k])(x[k+1] - x[k]) 得到牛顿迭代法的迭代公式:

x[k+1] = x[k] - f(x[k]) / f'(x[k])

回到求 8 的平方根

x[k+1] = x[k] - (x[k] - 8) / (2 * x[k]) = (x[k] + 8 / x[k]) / 2

就这样一直逼近到 x[k] * x[k] <= 8

class Solution {
    public int mySqrt(int x) {
        if (x == 0) return 0;
        long i = x;
        while(i > x / i)
            i = (i + x / i) / 2;
        return (int)i;
    }
}

python 版本

class Solution:
    def mySqrt(self, x):
        """
        :type x: int
        :rtype: int
        """
        if x == 0:
            return 0
        i = x
        while int(i) > int(x / i):
            i = (i + x / i) / 2
        return int(i)

热门文章

3977 次点击
所在节点    程序员
14 条回复
Kilerd
2018-09-15 23:42:50 +08:00
又来误人子弟了吗?
easylee
2018-09-15 23:46:38 +08:00
@Kilerd 此话怎讲?这里面有什么故事吗?
zhuangzhuang1988
2018-09-15 23:50:37 +08:00
sicp 101
broadliyn
2018-09-16 02:57:26 +08:00
这种求近似解的
高数里边极限等价替代、微分、泰勒公式套一下不就好啦。
broadliyn
2018-09-16 03:07:22 +08:00
也可以根据单调连续的函数零点左右的两个值乘积为负的特性再配合二分法可以逼出近似解。
broadliyn
2018-09-16 03:16:45 +08:00
除了上边的二分法,还有切线法,也就是 lz 的解法,没有 latex 排版表示看不懂 lz 在写什么。
此外还有割线法,如果原函数的导数复杂的话,可以用割线来近似替代切线。

上述出处是高数上册,微分中值定理与导数的应用里的泰勒公式、方程的近似解两章。
RqPS6rhmP3Nyn3Tm
2018-09-16 03:39:21 +08:00
@Kilerd 解法没错,而且牛顿法很难想到,效率也很高
puyo
2018-09-16 09:07:49 +08:00
用雷神之锤法可不可以
zingl
2018-09-16 12:01:19 +08:00
aliipay
2018-09-16 15:55:32 +08:00
@puyo 我在自己机器上跑可以,是牛顿迭代法的 10 倍。 放到 leetcode 就执行出错
CSM
2018-09-16 17:43:54 +08:00
@puyo 我看到这个题第一个想到的就是雷神之锤😂
Acceml
2018-09-16 22:55:45 +08:00
@Kilerd 你最正确,也最厉害,你尽管 diss,然而我并不 care 你...
ayyll
2018-09-16 23:14:43 +08:00
为啥要发这里呀。。。还不如找个 oi 或者 acm 群水呢 。。这里的人都对解题报告这种东西不感冒吧
20015jjw
2018-09-25 00:41:21 +08:00
@easylee 他之前写了个很烂的答案.. 然后还强行 defend.. 喷点主要是名企们看到那个答案肯定没 offer..

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/489728

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX