LeetCode 69: Sqrt(x) 求根号x(牛顿迭代法和二分查找法)

题目:
Implement int sqrt(int x).
Compute and return the square root of x.

分析:我们平常可能好少会自己去求解某个数的平方根,一般都是直接调用系统提供的函数,其实一般针对问题,并没有直接求解的公式,一般都是通过一个公式多次迭代来无限接近于这个解,这时,这个值就是我们要求的解
下面我们简要介绍2中方法:牛顿迭代法和二分查找法。

牛顿迭代法想必大家都比较熟悉,就是给定一个初始值,然后一直迭代来逼近方程的解。
这里写图片描述
比如对于上图,首先给定一个初始值X0,然后,通过这个初始值作函数的切线,与y=0交于一点,横坐标为x1, 在通过点(x1,f(x1))作函数的切线,与y=0交于点(横坐标为x2),这样一直下去,得到xn(若把xn代入方程得到的值与函数实际的值小于某一个很小的阈值,则我们认为xn就是函数的解

故要求解sqrt(x),即求解sqrt(t)(t=x), 即求函数 f ( x ) = x 2 − t = 0 f(x)=x^{2}-t=0 f(x)=x2t=0的解,我们给初始解赋一个初始值 x 0 x_{0} x0, 那么我们在点 ( x 0 , f ( x 0 ) ) (x_{0},f(x_{0})) (x0,f(x0))处对曲线作切线, 得到如下方程 y − f ( x 0 ) = f ( x 0 ) ′ ( x − x 0 ) y-f(x_{0})=f(x_{0})'(x-x_{0}) yf(x0)=f(x0)(xx0),令y=0, 解得 x = x 0 / 2 + t / ( 2 x 0 ) x=x_{0}/2+t/(2x_{0}) x=x0/2+t/(2x0), 则迭代的解 x 1 = x 0 / 2 + t / ( 2 x 0 ) x_{1}=x_{0}/2+t/(2x_{0}) x1=x0/2+t/(2x0),像这样依次迭代 x n = x n − 1 / 2 + t / ( 2 x n − 1 ) x_{n}=x_{n-1}/2+t/(2x_{n-1}) xn=xn1/2+t/(2xn1), 若 f ( x n ) f(x_{n}) f(xn)很接近于0(与0的差绝对值小于某个阈值),这迭代终止, x n x_{n} xn即为函数的解。

int mySqrt(int x) 
{
    if(x==0||x==1)
        return x;
    double x0=x;
    double t=x;
    x0=x0/2+t/(2*x0);
    while(fabs(x0*x0-t)>0.00001)
    {
        x0=x0/2+t/(2*x0);
    }
    cout<<x0<<endl;
    return int(x0);
}

另一种方法就是二分查找法了,思路很简单,就不介绍了,直接上代码:

int mySqrt(int x) 
{
    if(x==0||x==1)
        return x;
    int mid,left=1,right=x;
    while(left<right)
    {
        mid=left+(right-left)/2;
        if(mid>x/mid)
            right=mid-1;
        else if(mid==x/mid)
            return mid;
        else
        {
            if((mid+1)>x/(mid+1))
                return mid;
            if((mid+1)==x/(mid+1))
                return mid+1;
            left=mid+1;
        }
    }
    return (left+right)/2;
}

法三,梯度下降法:

## 注意梯度下降计算的时候初始值的设置(参数初始化) && 学习率
## 牛顿法一般就通过泰勒公式展开
## loss = (x*x-n)^2
import random
import matplotlib.pyplot as plt
class Solutin():
    def gradient_descent(self,n):
        # 随机初始化
        x = float(random.randint(50, 100))
        # 学习率
        lr = 0.00001
        # 记录损失
        loss = []
        cnt = 0
        # 损失阈值
        while (abs(x ** 2 - n) > 0.5):
            # x(n+1) = x(n) - lr * g(x(n))
            x = x - lr * 4 * x * (x ** 2 - n)
            if cnt % 50 == 0:
                print('x: '+str(x)+',     cnt: '+str(cnt))
            cnt += 1
            # 记录损失
            loss.append((x ** 2 - n)**2)
        return loss,x

if __name__ == '__main__':
    n=2
    loss,a = Solutin().gradient_descent(n)
    print( a)

    # 画损失图
    x = range(len(loss))
    plt.plot(x, loss, color='b')
    plt.xlim(0,1000)
    plt.show()
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值