Leetcode 69. Sqrt(x)及其扩展(有/无精度、二分法、牛顿法)详解
Leetcode 69. Sqrt(x) Easy
https://leetcode.com/problems/sqrtx/
Implement int sqrt(int x).
Compute and return the square root of x, where x is guaranteed to be a non-negative integer.
Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned.
Example 1:
Input: 4
Output: 2
Example 2:
Input: 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since
the decimal part is truncated, 2 is returned.
分析:
leetcode上的这个不带精度要求,且输出一个整数即可(其实可以当成精度要求小于等于1)。
方法一:(二分法)
对于本题,最直观的方法就是二分法。使用二分法时,需要注意有三个指针,分别指向前中后(pre、medium、last,在书写、习惯、理解上,一般用left、mid、right进行表示,或者用start、mid、end)。此外,循环结束的条件也需要在书写程序之前想好,当然这也是本题的难点。
边界条件怎么确定呢?
假设left < right时循环,当left等于right时循环结束,并返回left或right,此时有left=right=mid。那么可以取一个整数进行实验:比如8。
第一次循环:
mid = (1 + 8)/2 = 4 (整数除法默认向下取整)
mid > 8/mid
right = mid - 1 = 3
left = 1
第二次循环:
mid = (1 + 3)/2 = 2
mid < 8/mid
left = mid + 1 = 3
right = 3
此时由于left == right 则跳出循环,返回的是3,但是这不应该是正确答案。如果在循环条件中加上等于,即left <= right,那么下一步还会有一次循环:
第三次循环:(新增的)
mid = 3
mid > 8/mid
right = mid - 1 = 2
left = 3
此时left > righ结束循环。写到这里,我们发现,如果在循环结束时,对于此例子,返回right是比较合适的。这是个例吗,还是都是这样?
比如x=10,那么mid的变化过程将是:5->2->3,此时10/3 == 3,直接返回了。再如x=11,那么mid变化过程将是:5->2->3,此时11/3 == 3,直接返回了。
再比如x=12,那么mid变化过程将是:6->3->4(此时left=4,right=5)->4(left=4,right=4)->此时right-1,变为left = 4, right = 3,返回right。
所以right必为返回值(在不存在mid == x / mid的条件下)
至于为什么,可以细想一下,我也没想明白,给出理论解释。直观感觉是开根号为向下取整,而返回right时,right < left,正好算是向下取整。
注意:之所以要写成除法的形式,是因为如果两个大数相乘,容易超内存。
int mySqrt(int x) {
int left = ; // left不能取0;因为如果x=1,那么(0+1)/2 = 0,导致mid等于0,做除法的时候会报错
int right = x;
while (left <= right) {
// int mid = (left + right) / 2; ——> 不要这么写,是因为如果right很大,left+right可能会超过整型最大值
int mid = left + (right - left) / 2;
if (mid == x / mid) {
return mid;
}
else if (mid > x / mid) {
right = mid - ;
}
else { // mid < x / mid
left = mid + ;
}
}
return right;
}
方法二:(牛顿法)
下面介绍牛顿法/牛顿迭代法。使用牛顿法千万不要死记硬背公式,要明白推导过程。牛顿法是用来求方程的近似根。通过使用f(x)的泰勒级数的前几项来寻找f(x)=0的根。(思考,和xgboost中使用牛顿法有什么区别)
关于泰勒级数的介绍:(说的不错)
https://baike.baidu.com/item/%E6%B3%B0%E5%8B%92%E7%BA%A7%E6%95%B0
https://zh.wikipedia.org/wiki/%E6%B3%B0%E5%8B%92%E7%BA%A7%E6%95%B0
关于牛顿法/牛顿迭代法:
https://baike.baidu.com/item/%E7%89%9B%E9%A1%BF%E8%BF%AD%E4%BB%A3%E6%B3%95 (百科介绍的太好了)
https://www.zhihu.com/question/20690553
https://www.cnblogs.com/wangkundentisy/p/8118007.html
(介绍了牛顿迭代法的使用,主要对问题进行求根转化后,然后求切线与x轴交点,并进行迭代更新此处更适合用来求根/零点,和下面这个优化算法是不太一样的)
https://blog.csdn.net/google19890102/article/details/41087931
(作为优化算法的牛顿法,整体思想就是利用迭代点处的一阶导数(梯度)和二阶导数(Hessen矩阵)对目标函数进行二次函数近似,然后把二次模型的极小点作为新的迭代点,并不断重复这一过程,直至求得满足精度的近似极小值。这就和XGBoost对损失函数进行二阶泰勒展开是相同的原理,且用目标函数对f_t-1(x)求一阶导数,所以说利用了牛顿法;而且在XGBoost中,求得的f_t-1(x)或者说w_q(x)即是下一次更新的叶子节点的权重。结合着论文和这篇博客还是比较容易懂,值得反复看)
为什么优化和求根都叫牛顿法呢?明明在求根和零点问题上,就是作切线嘛,明明没有泰勒展开啊,看看百度百科的“回答”(让我豁然开朗):

注意的关键词:非线性方程,泰勒级数,取线性部分,近似方程。
下面进行详细分析,推导出迭代关系式(用iPad手写推导过程),并给出代码:



总结:
由上分析我们可以发现,由牛顿法和切线法得来的递推公式是相同的,我们姑且可以认为切线法是牛顿法的几何表示。
此时,所谓的牛顿法对我已不再神秘,希望对你也一样如此!
int mySqrt(int x) {
long long ans = x;
while (ans * ans > x) { // 其实,我很疑惑:如果ans很大的情况下,ans*ans不应该会报错吗
ans = (ans + x / ans) / ; // 由公式化简得来
}
return ans;
}
至此,Leetcode上的这道 “Easy” 题目已经解决。但是往往在面试或实际问题中,要求最后得到的结果具备一定精度,即ans*ans - x < ε。此外,如果要求 ans值满足某一精度,我们就必须使用sqrt()求出其真实开根号值,然后作为判断条件。下面对一种进行代码书写,整体思路和不带精度相同,但是要注意需要把int型转为double型!
二分法:
double mySqrt(double x, double epsilon) {
double left = 1.0;
double right = x;
double mid = left + (right - left) / ;
while (fabs(mid * mid - x) > epsilon) { // 默认mid * mid不会超过范围,否则这道题就麻烦了
if (mid * mid > x) {
right = mid;
}
else if (mid * mid < x) {
left = mid;
}
else {
return mid;
}
mid = left + (right - left) / ;
}
return mid;
}
牛顿法:
double mySqrt(double x, double epsilon) {
double ans = x;
while (fabs(ans * ans - x) > epsilon) {
ans = (ans + x / ans) / ;
}
return ans;
}
注:
关于数学符号表示的知识,如:epsilon :ε
Leetcode 69. Sqrt(x)及其扩展(有/无精度、二分法、牛顿法)详解的更多相关文章
- C++版 - Leetcode 69. Sqrt(x) 解题报告【C库函数sqrt(x)模拟-求平方根】
69. Sqrt(x) Total Accepted: 93296 Total Submissions: 368340 Difficulty: Medium 提交网址: https://leetcod ...
- [LeetCode] 69. Sqrt(x) 求平方根
Implement int sqrt(int x). Compute and return the square root of x, where x is guaranteed to be a no ...
- LeetCode 69. Sqrt(x) (平方根)
Implement int sqrt(int x). Compute and return the square root of x. x is guaranteed to be a non-nega ...
- Leetcode 69. Sqrt(x)
Implement int sqrt(int x). 思路: Binary Search class Solution(object): def mySqrt(self, x): "&quo ...
- (二分查找 拓展) leetcode 69. Sqrt(x)
Implement int sqrt(int x). Compute and return the square root of x, where x is guaranteed to be a no ...
- [LeetCode] 69. Sqrt(x)_Easy tag: Binary Search
Implement int sqrt(int x). Compute and return the square root of x, where x is guaranteed to be a no ...
- Leetcode 69 Sqrt(x) 二分查找(二分答案)
可怕的同时考数值溢出和二分的酱油题之一,常在各种小公司的笔试中充当大题来给你好看... 题意很简单,在<二分查找综述>中有描述. 重点:使用简单粗暴的long long来避免溢出,二分均方 ...
- c++ LeetCode(初级数组篇)十一道算法例题代码详解(一)
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/10940636.html 唉!最近忙着面试找实习,然后都是面试的很多是leetcode的算法题, ...
- jQuery实现form表单基于ajax无刷新提交方法详解
本文实例讲述了jQuery实现form表单基于ajax无刷新提交方法.分享给大家供大家参考,具体如下: 首先,新建Login.html页面: <!DOCTYPE html PUBLIC &quo ...
随机推荐
- MySQL常见水平分表技术方案
根据经验,Mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉:水平分表能够很大程度较少这些压力. 1.按时间分表 这种分表方式有一定的局限性,当数据有较强的实效 ...
- BZOJ 2229 / Luogu P3329 [ZJOI2011]最小割 (分治最小割板题)
题面 求所有点对的最小割中<=c的数量 分析 分治最小割板题 首先,注意这样一个事实:如果(X,Y)是某个s1-t1最小割,(Z,W)是某个s2-t2最小割,那么X∩Z.X∩W.Y∩Z.Y∩W这 ...
- Educational Codeforces Round 74 (Rated for Div. 2) C. Standard Free2play
链接: https://codeforces.com/contest/1238/problem/C 题意: You are playing a game where your character sh ...
- fadeTo([[speed],opacity,[easing],[fn]])
fadeTo([[speed],opacity,[easing],[fn]]) 概述 把所有匹配元素的不透明度以渐进方式调整到指定的不透明度,并在动画完成后可选地触发一个回调函数.大理石机械构件维修 ...
- 【转载】Maven安装配置+ GIt&SVN + Jenkins详细配置 软件项目管理 持续集成实验
原文地址: https://www.cnblogs.com/clownice/p/5395933.html 以下是学习笔记: Jenkins是一款开源持续集成的软件,实现集成的自动化 自动构建工具:M ...
- 【spring源码分析】IOC容器初始化——查漏补缺(二)
前言:在[spring源码分析]IOC容器初始化(八)中多次提到了前置处理与后置处理,本篇文章针对此问题进行分析.Spring对前置处理或后置处理主要通过BeanPostProcessor进行实现. ...
- 笔记三(UEFI详解)
1.SEC 安全验证 SEC(Security Phase)阶段是平台初始化的第一个阶段,计算机系统加电后进入这个阶段. 1)接收并处理系统启动和重启信号:系统加点信号.系统重启信号.系统运行过程中的 ...
- K-Means算法及代码实现
1.K-Means算法 K-Means算法,也被称为K-平均或K-均值算法,是一种广泛使用的聚类算法.K-Means算法是聚焦于相似的无监督的算法,以距离作为数据对象间相似性度量的标准,即数据对象间的 ...
- Jenkins与gitlib实现自动化部署与持续构建
Jenkins概念 Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测试和 ...
- 第11组 Beta冲刺(5/5)
第11组 Beta冲刺(5/5) 队名 不知道叫什么团队 组长博客 https://www.cnblogs.com/xxylac/p/12031050.html 作业博客 https://edu. ...