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)及其扩展(有/无精度、二分法、牛顿法)详解的更多相关文章

  1. C++版 - Leetcode 69. Sqrt(x) 解题报告【C库函数sqrt(x)模拟-求平方根】

    69. Sqrt(x) Total Accepted: 93296 Total Submissions: 368340 Difficulty: Medium 提交网址: https://leetcod ...

  2. [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 ...

  3. 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 ...

  4. Leetcode 69. Sqrt(x)

    Implement int sqrt(int x). 思路: Binary Search class Solution(object): def mySqrt(self, x): "&quo ...

  5. (二分查找 拓展) 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 ...

  6. [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 ...

  7. Leetcode 69 Sqrt(x) 二分查找(二分答案)

    可怕的同时考数值溢出和二分的酱油题之一,常在各种小公司的笔试中充当大题来给你好看... 题意很简单,在<二分查找综述>中有描述. 重点:使用简单粗暴的long long来避免溢出,二分均方 ...

  8. c++ LeetCode(初级数组篇)十一道算法例题代码详解(一)

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/10940636.html 唉!最近忙着面试找实习,然后都是面试的很多是leetcode的算法题, ...

  9. jQuery实现form表单基于ajax无刷新提交方法详解

    本文实例讲述了jQuery实现form表单基于ajax无刷新提交方法.分享给大家供大家参考,具体如下: 首先,新建Login.html页面: <!DOCTYPE html PUBLIC &quo ...

随机推荐

  1. hbase实践之写流程拾遗

    keyvalue KeyValue中包含了丰富的自我描述信息: KeyValue是支撑"稀疏矩阵"设计的一个关键点:一些Key相同的任意数量的独立KeyValue就可以构成一行数据 ...

  2. 第107题:二叉树的层次遍历II

    一. 问题描述 给定一个二叉树,返回其节点值自底向上的层次遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 例如: 给定二叉树 [3,9,20,null,null,15,7], 3 ...

  3. Oracle 中文转字母 函数

    CREATE OR REPLACE FUNCTION F_TRANS_PINYIN_CAPITAL(P_NAME IN VARCHAR2) RETURN VARCHAR2 AS V_COMPARE V ...

  4. 五十四.自定义镜像及仓库、持久化存储 、 Docker网络架构

    1. 制作自定义镜像(base基础镜像,搭建共性环境) 基于centos镜像使用commit创建新的镜像文件 基于centos镜像使用Dockerfile文件创建一个新的镜像文件   1.1 使用镜像 ...

  5. CKEditor本地图片自动上传插件

    由于工作需要必须将word文档内容粘贴到编辑器中使用 但发现word中的图片粘贴后变成了file:///xxxx.jpg这种内容,如果上传到服务器后其他人也访问不了,网上找了很多编辑器发现没有一个能直 ...

  6. CSP-S模拟测试 88 题解

    T1 queue: 考场写出dp柿子后觉得很斜率优化,然后因为理解错了题觉得斜率优化完全不可做,只打了暴力. 实际上他是可以乱序的,所以直接sort,正确性比较显然,贪心可证,然后就是个sb斜率优化d ...

  7. 一步一步配置AWS ELB Https证书

    第一步:生成CSR 要配置证书,我们首先需要创建一个CSR来向证书提供商申请证书.这个过程我们可以通过IIS中的工具来生成. 然后需要填写如下信息: 下一步后选择文件名后我们就可以创建出CSR 文件了 ...

  8. 微信小程序之简单记账本开发记录(二)

    1.打开开发者工具 2.从微信公众平台上获取到appid,或者使用测试号. 项目的大致目录如下: 一个小程序主体部分由三个文件组成,必须放在项目的根目录中 以app为开头的文件名用来布置作用于整个项目 ...

  9. Java高并发下的 “单例模式”

    前言:单例模式大家应该很熟悉了,我在这里就自己总结一下自己这段时间学到的单例相关的知识. 单例模式的目的:保证一个类只有单一的实例,也就是说你无法通过new来创建这个类的一个新实例. 单例模式的意义: ...

  10. Flutter移动电商实战 --(25)列表页_使用Provide控制子类-1

    主要是二级分类的UI布局 生成我们的右侧动态类 定义list变量 开始写里面的子项,把每一个小的写了 再拼成一个大的 这样我们的小类就写完了 开始写我的大类别:是一个横向的ListView.写横向的L ...