算法题:求正实数x的平方根 (注意不是整数)& 求方程的根

算法题:求正实数x的平方根

69. x 的平方根

不同于LC69,面试题要求x是正实数,而不是整数。并且需要注意x可能是小数,此时x的平方根是大于x的

二分法

https://blog.csdn.net/weixin_27625589/article/details/116221090

def mySqrt2(x): # 正实数x的平方根,注意是实数、注意可能是正的小数
    left = 0
    right = max(x, 1.0) # x是正小数的情况下,平方根比x大,但肯定是小于1.0的

    while left < right:
        mid = (left + right) / 2.0  # 实数
        # print(left, right, mid, mid * mid)

        if abs(mid * mid - x) < 1e-6:   # 精度
            return mid

        if mid * mid > x:
            right = mid     # 实数,不是mid-1
        elif mid * mid < x:
            left = mid
 
print(mySqrt2(10), mySqrt2(0.09))
# 3.162277638912201 0.2999992370605469

梯度下降法

https://leetcode-cn.com/problems/sqrtx/solution/bu-chong-yi-ge-ti-du-xia-jiang-fa-by-tra-fkds/
!image

import math
class Solution:
    # 请注意,此处的参数原题是 x,
    # 为了更好理解改为了 t, 而 x 用于迭代过程,和公式相匹配 
    def mySqrt(self, t: int) -> int:
        # 初始值,注意,初始值不能设为0,否则所有迭代结果均为0
        x = 1
        # 定义学习率
        learning_rate = 0.00001
        # 定义精度
        eps = 1e-5
        while math.fabs(x ** 2 - t) > eps:
            # 梯度下降迭代过程
            x = x - learning_rate * self.gradient(x, t)
  
        # res = int(x)
        # # 注意边界值,因为 int 会向下取整,所以需判断 int+1 是否更接近答案
        # return (res + 1) if (res+1)**2 <= t else res
        return x  # 返回实数,不要取整 
  
    def gradient(self, x, t):
        return 4 * x * (x ** 2 - t)

s = Solution()
print(s.mySqrt(0.09))
# 0.30001666619774

假如现在要求的是根号2 即 \(x^2=2\) 的解 使用梯度下降法,梯度下降主要通过求梯度为0的点,得到凸函数的全局最小值 \(x^2\) 是凸函数。首先构建损失函数为凸函数的目标函数, 使得目标函数的最小值对应的是我们要求的值

\(x^2 = t\):逼近t的损失函数是 \(L = (x^2 - t )^2\), 对x求梯度是:\(dL/dx = 4*x*(x^2 - t)\)

def gradient_descent(n):
    x = float(random.randint(1, 100))
    array = []	# 保存每一步的估计
    while (abs(x ** 2 - n) > 0.0001):	# 精度是0.0001, 也可以使用梯度绝对值不接近0作为继续循环的条件
        x = x - 0.00001 * 4 * x * (x ** 2 - n)	# 学习率是0.00001, 
        array.append(x)
    return array

n=10
array = gradient_descent(n)
# x = range(len(array))
# plt.plot(x, array, color='b')
# plt.show()
import math
print(math.sqrt(n), array[-1])

牛顿法

https://blog.csdn.net/dpengwang/article/details/99092278

https://blog.csdn.net/songyunli1111/article/details/90474836

image

import random
import matplotlib.pyplot as plt
import math
def Newton(n):	# target
    array = []	# 保存每一步估计
    x = float(random.randint(1, 100))	# 随机初始点
    while(abs(x**2 - n) > 0.000000001):	# 精度,	也可以使用梯度绝对值不接近0作为继续循环的条件
        x = x - (x**2 - n ) / (2*x)	# 牛顿法公式
        array.append(x)
    return array

n=10
array = Newton(n)
# x = range(len(array))
# plt.plot(x, array, color='b')
# plt.show()
print(math.sqrt(n), array[-1])

补充:数值计算方法:二分法求解方程的根

https://blog.csdn.net/weixin_27625589/article/details/116221090

def fun(x):
    return x ** 2 + x - 6

def newton(a,b,e):  # e 是 精度
    x = (a + b)/2.0
    if abs(b-a) < e:
        return x
    else:

        if fun(a) * fun(x) < 0:
            return newton(a, x, e)
        else:
            return newton(x, b, e)

print(newton(-5, 0, 5e-5))
print(newton(0, 5, 5e-5))
# -3.000011444091797
# 1.9999885559082031
# 二分法求解方程的根
def fun(x):
    return x ** 2 + x - 6

def binSearch(a, b):    # 当 fun(a), fun(b)异号,且设只有一个根的时候
    left, right = a, b
    while left <= right:
        mid = (left + right) / 2.0
        if abs(fun(mid)) < 1e-6:
            return mid
        if fun(mid) * fun(left) < 0:	# left和mid的函数值异号
            right = mid
        else:
            left = mid
print(binSearch(-5, 0), "\n", binSearch(0, 5))
# -3.0000001192092896 
#  1.9999998807907104
posted @ 2022-05-07 09:48  麦克斯的园丁  阅读(211)  评论(0编辑  收藏  举报