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 ...
随机推荐
- python高性能编程方法一
python高性能编程方法一 阅读 Zen of Python,在Python解析器中输入 import this. 一个犀利的Python新手可能会注意到"解析"一词, 认为 ...
- C语言学习系列(二)面向过程和面向对象
一.基本定义 (一).面向过程(procedure oriented programming POP) 面向过程是分析解决问题的步骤,然后用函数把这些步骤一步一步的实现,然后在使用的时候一一调用则可. ...
- 9、Spring Boot 2.x 集成 Thymeleaf
1.9 Spring Boot 2.x 集成 Thymeleaf 完整源码: Spring-Boot-Demos 1.9.1 在pom中引入依赖 <dependency> <grou ...
- [Codevs] 矩形面积求并
http://codevs.cn/problem/3044/ 线段树扫描线矩形面积求并 基本思路就是将每个矩形的长(平行于x轴的边)投影到线段树上 下边+1,上边-1: 然后根据线段树的权值和与相邻两 ...
- The 10th Shandong Provincial Collegiate Programming Contest
目录 Contest Info Solutions A. Calandar B. Flipping Game C. Wandering Robot D. Game on a Graph E. BaoB ...
- WPF中,Grid与Table的区别(英文)-转载
原文地址:http://blog.csdn.net/johnsuna/article/details/1742799 How is Grid Different from Table?Table an ...
- 基于nodejs将mongodb的数据实时同步到elasticsearch
一.前言 因公司需要选用elasticsearch做全文检索,持久化存储选用的是mongodb,但是希望mongodb里面的数据发生改变可以实时同步到elasticsearch上,一开始主要使用ela ...
- PyTricks-Differebt ways to test multiple flags at once in
x, y, z = 0, 1, 0 if x == 1 or y == 1 or z == 1: print('passed') if 1 in (x, y, z): print('passed') ...
- 分享一个自己做的SpringMVC的PPT,由于比较忙只写了一些重要的部分
- mysql索引分类
mysql索引分类 一.总结 一句话总结: 主键索引:设定为主键后数据库会自动建立索引,innodb为聚簇索引 单值索引:一个索引只包含单个列,一个表可以有多个单列索引:CREATE INDEX id ...