1.题目要求

实现 int sqrt(int x) 函数。

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

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

示例 1:

输入: 4
输出: 2

示例 2:

输入: 8
输出: 2
说明: 8 的平方根是 2.82842...,
由于返回类型是整数,小数部分将被舍去。

2.初次尝试

这道题很明显不是让我们调用 Math.sqrt() 方法来计算,而是自己实现一个求平方根的算法。第一反应想到的方法是暴力循环求解!从 1 开始依次往后求平方数,当平方数等于 x 时,返回 i ;当平方数大于 x 时,返回 i - 1。

 class Solution {
public int mySqrt(int x) {
for(int i = 0; i <= x; i++) {
if(i * i >= x){
if(i * i == x)
return i;
else
return i - 1;
}
}
return 0;
}
}

这种方案通过了测试,但是成绩惨不忍睹:

执行用时 : 105 ms, 在Sqrt(x)的Java提交中击败了5.53% 的用户
内存消耗 : 33.1 MB, 在Sqrt(x)的Java提交中击败了83.60% 的用户

好奇心驱使下,我用了 Math.sqrt() 方法又提交了一遍答案:

 class Solution {
public int mySqrt(int x) {
return (int)Math.sqrt(x);
}
}

成绩有点无解:

执行用时 : 5 ms, 在Sqrt(x)的Java提交中击败了99.24% 的用户
内存消耗 : 33.2 MB, 在Sqrt(x)的Java提交中击败了80.86% 的用户

这样一道乍看之下有点“蠢”的题目,其实有很多可以深究的地方。Math.sqrt() 用的是什么算法?求平方数的算法还有哪些?

Google 了一下“求平方根”,看到了两个出镜率最高的名词,一个是我们耳熟能详的“二分法”,另一个则是我第一次听说的“牛顿迭代法“。难得五一假期有空,决定了解一下”牛顿迭代法“并自己写出基于此算法的解题答案。

3.牛顿迭代法

我是根据知乎上一个回答了解牛顿迭代法的,链接贴出来了,有兴趣的朋友可以移步去看一下。这里简单的通过他的文章说明一下思路。

如何通俗易懂地讲解牛顿迭代法求开方?数值分析?​www.zhihu.com

这种算法的一个重要的思想是:切线是曲线的线性逼近。基于这种思想,牛顿尝试用切线来研究曲线的问题,例如用切线的根近似的求出曲线的根。然后他观察到一个现象,当在曲线上取某一点作切线时,以该切线的根作垂线,在垂线和曲线的交点处再作切线,以此循环往复,切线的根逐渐会逼近曲线的根。如图所示(A点时第一个取的点)。

当然,其实这种迭代并不是一定能保证会向曲线的根逼近,具体原因可以移步上述链接。但是求二次方程的根是没有问题的。

4.牛顿迭代法求平方根

回归到题目,求 a 的平方根,实际上可以转换成求二次方程 x^2 - a = 0 的解的问题。然后可以作出该二次方程的曲线,通过迭代逼近曲线 y = 0 处 x 的值,该 x 即是需要求得的答案。提现到程序中如下:

 class Solution {
public int mySqrt(int x) {
if(x == 1)
return 1;
double _x = x >> 1;
double _y = _x * _x - x;
double a = (-_y + 2 * _x * _x) / 2 / _x;
while(_y > 0.1 || _y < -0.1){
_x = a;
_y = _x * _x - x;
a = (-_y + 2 * _x * _x) / 2 / _x;
}
return (int)_x;
}
}

这个程序很直观的反应了迭代的过程,"_x" 是二次方程的横坐标,"_y" 是方程的纵坐标,"a" 是切线与 x 轴的交点处的横坐标。选取的第一点为 x / 2 作为横坐标,当 _y 的值逼近 0 的时候,返回 _x。该方法的成绩很接近 Math.sqrt(),结果为:

执行用时 : 6 ms, 在Sqrt(x)的Java提交中击败了92.91% 的用户
内存消耗 : 33.7 MB, 在Sqrt(x)的Java提交中击败了75.11% 的用户

5.简化

这里其实可以注意到,该二次方程一定是关于 y 轴对称的,而且二次方程在迭代过程中,若初始点在根的右边,则迭代的点会一直出现在根的右边,且一直逼近根。我们要找的其实是比根小的最大的整数,可以把 a 换成 int 类型,在逼近过程中,当 a 第一次小于等于 x / a 时,返回 a。

对程序进行简化,去掉一些不必要的参数,优化最后判断足够逼近的方式,最后程序为:

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

LeetCode 69 题的更多相关文章

  1. leetcode刷题指南

    转载自:http://blog.csdn.net/lnho2015/article/details/50962989 以下是我个人做题过程中的一些体会: 1. LeetCode的题库越来越大,截止到目 ...

  2. LeetCode算法题-Sum of Two Integers(Java实现)

    这是悦乐书的第210次更新,第222篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第78题(顺位题号是371).计算两个整数a和b的总和,但不允许使用运算符+和 - .例 ...

  3. LeetCode算法题-Sqrt(Java实现)

    这是悦乐书的第158次更新,第160篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第17题(顺位题号是69). 计算并返回x的平方根,其中x保证为非负整数. 由于返回类型 ...

  4. C#LeetCode刷题-二分查找​​​​​​​

    二分查找篇 # 题名 刷题 通过率 难度 4 两个排序数组的中位数 C#LeetCode刷题之#4-两个排序数组的中位数(Median of Two Sorted Arrays)-该题未达最优解 30 ...

  5. C#LeetCode刷题-数学

    数学篇 # 题名 刷题 通过率 难度 2 两数相加   29.0% 中等 7 反转整数 C#LeetCode刷题之#7-反转整数(Reverse Integer) 28.6% 简单 8 字符串转整数 ...

  6. leetcode刷题目录

    leetcode刷题目录 1. 两数之和 2. 两数相加 3. 无重复字符的最长子串 4. 寻找两个有序数组的中位数 5. 最长回文子串 6. Z 字形变换 7. 整数反转 8. 字符串转换整数 (a ...

  7. 这样leetcode简单题都更完了

    这样leetcode简单题都更完了,作为水题王的我开始要更新leetcode中等题和难题了,有些挖了很久的坑也将在在这个阶段一一揭晓,接下来的算法性更强,我就要开始分专题更新题目,而不是再以我的A题顺 ...

  8. 48. leetcode 105题 由树的前序序列和中序序列构建树结构

    leetcode 105题,由树的前序序列和中序序列构建树结构.详细解答参考<剑指offer>page56. 先序遍历结果的第一个节点为根节点,在中序遍历结果中找到根节点的位置.然后就可以 ...

  9. LeetCode算法题-Subdomain Visit Count(Java实现)

    这是悦乐书的第320次更新,第341篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第189题(顺位题号是811).像"discuss.leetcode.com& ...

随机推荐

  1. log4j 路径环境变量配置和log4j加载配置

    1.lo4j日志路径从环境变量读取,log4j.xml配置如下: 具体配置如下: log4j.appender.R.Encoding=UTF-8 log4j.appender.R=org.apache ...

  2. 浏览器和服务器 对post get请求 url长度限制

    1. URL长度限制 2. Post数据的长度限制 3. Cookie的长度限制 1. GET  URL长度限制 在Http1.1协议中并没有提出针对URL的长度进行限制,RFC协议里面是这样描述的, ...

  3. elastica安装

    https://www.elastic.co/guide/en/elasticsearch/reference/current/zip-targz.html

  4. javascript 阻止事件冒泡 cancelBubble

    javascript简单的阻止事件冒泡,可以使用事件的cancelBubble方法为true: html部分 <button id="btn1">点击显示div< ...

  5. ajax访问json文件缓存问题

    ajax访问json文件,json文件改动,访问的时候也不能及时看到改动后的内容. 这是因为浏览器缓存的原因. 在这时候就需要清除浏览器的缓存或者加上一个标记,让ajax访问文件的时候知道这是一个新的 ...

  6. css3中animation的应用

    1.css3 的相关属性: 相关代码: div { animation-name: myfirst; //动画的名称 animation-duration: 5s; //动画一个周期需要5秒 anim ...

  7. URAL1519 Formula 1 —— 插头DP

    题目链接:https://vjudge.net/problem/URAL-1519 1519. Formula 1 Time limit: 1.0 secondMemory limit: 64 MB ...

  8. YTU 2452: 麦克劳林用于函数求值

    2452: 麦克劳林用于函数求值 时间限制: 1 Sec  内存限制: 128 MB 提交: 18  解决: 12 题目描述 泰勒公式是一个用函数在某点的信息描述其附近取值的公式.如果函数足够光滑的话 ...

  9. Android的三种主流资源尺寸

    Android三种主流资源屏幕尺寸:QVGA.HVGA.WVGA VGA的分辨率是640x480像素 QVGA(Quarter VGA)就是320x240,即VGA分辨率的1/4 HVGA(Half ...

  10. 【POJ 1655】 Balancing Act

    [题目链接] 点击打开链接 [算法] 树形DP求树的重心 [代码] #include <algorithm> #include <bitset> #include <cc ...