序言
今天是刷LT的一天,好好干饭,好好努力,好好加油哦
这几天准备好好刷二分法的相关LT题
Leetcode题目:
实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去
例子
输入: 4
输出: 2
----------------
输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
本题是一道常见的面试题,面试官一般会要求面试者在不使用
x
\sqrt{x}
x函数的情况下,得到 x的平方根的整数部分。既然这样,我们就用二分法来这道题:
我们知道答案肯定在[0,x]中间选择,于是这道题的下界是 bgn = 0 ,上界 是 end = x
通过比较 数值的平方 和x 的大小
def mySqrt(x):
bgn = 0
end = x
while bgn <= end:
mid = (bgn + end)//2
tmp = mid * mid
if tmp > x :
end = mid -1
elif tmp < x :
bgn = mid +1
elif tmp = x:
return mid
return end
时间复杂度分析
- 时间复杂度:O(log x),即为二分查找需要的次数。
- 空间复杂度:O(1)
方法二:牛顿法
这道题相当于是求函数
f
(
x
)
=
x
2
−
C
f(x)=x^2-C
f(x)=x2−C的零值问题。其中C等于输入值
其原理是
(1)首先随机选一个数作为初始值 作为
x
0
x_0
x0
则迭代的第二个数为 函数在初始值的切线与横轴的交点的横坐标
即先求切线 的斜率 k =
2
x
0
2 x_0
2x0 加上 初始值坐标为
(
x
0
,
f
(
x
0
)
)
(x_0, f(x_0))
(x0,f(x0))
则切线方程为
y
=
2
x
0
(
x
−
x
0
)
+
x
0
2
−
C
y=2x_0(x-x_0) + x_0^2 - C
y=2x0(x−x0)+x02−C
(2)然后求切线在横坐标的值:
2
x
0
(
x
−
x
0
)
+
x
0
2
−
C
=
0
2x_0(x-x_0) + x_0^2 - C = 0
2x0(x−x0)+x02−C=0
即
x
=
(
C
−
x
0
2
)
/
2
X
0
+
X
0
=
C
/
2
X
0
−
1
/
2
X
0
+
X
0
=
1
/
2
(
C
/
X
0
+
X
0
)
x = (C-x_0^2)/2X_0 + X_0= C/2X_0 - 1/2X_0 +X_0= 1/2(C/X_0 +X_0)
x=(C−x02)/2X0+X0=C/2X0−1/2X0+X0=1/2(C/X0+X0)
即得到了迭代方程式
所以
X
1
=
1
/
2
(
C
/
X
0
+
X
0
)
X_1 = 1/2(C/X_0 + X_0)
X1=1/2(C/X0+X0)
那么迭代到何时才算结束?
当相连的X之间的差值很小的时候,则证明就在零值那里徘徊了,一般差值我们设为
1
0
−
6
10^{-6}
10−6
代码如下:
def mySqrt(x):
#排除例外情况
if x == 0:
return x
#设定初始值
x0 = x
while True:
xi = 1/2 * (x/x01 - x0)
diff = abs(xi-x0)
if diff < 1e-6:
break
x0 = xi
return int(x0)
时间复杂度分析
- 时间复杂度:O(log x),此方法是二次收敛的,相较于二分查找更快。
- 空间复杂度:O(1)
题目二
Leetcode题目:
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素
二分法思路是:
固定数组的第一个数开始,使用二分法查询第二个数的位置,时间复杂度应该为 O(nlog(n))
def twoSum(numbers, target):
n = len(numbers)
for i in range(n):
#固定i这个数,从i往右边开始寻找 第二个数
bgn = i+1
end = n -1
while bgn <= end:
mid = (bgn + end)//2
tmp = numbers[mid]
if tmp > target - numbers[i]:
end = mid -1
if tmp < target - numbers[i]:
bgn = mid + 1
if tmp == target - numbers[i]:
return [i,mid]
return []
复杂度分析
时间复杂度:O(n log n)
空间复杂度:O(1)x
方法二:双指针
初始时两个指针分别指向第一个元素位置和最后一个元素的位置。每次计算两个指针指向的两个元素之和,并和目标值比较。
如果两个元素之和等于目标值,则发现了唯一解。
如果两个元素之和小于目标值,则将左侧指针右移一位。
如果两个元素之和大于目标值,则将右侧指针左移一位。
def twoSum(numbers, target):
bgn = 0
end = len(numbers)-1
while bgn < end:
tmp = numbers[bgn] + numbers[end]
if tmp > target:
end = end -1
if tmp < target:
bgn = bgn + 1
if tmp == target:
return [bgn + 1, end + 1]
return []
时间复杂度:O(n),其中 nn 是数组的长度。两个指针移动的总次数最多为 n 次。
空间复杂度:O(1)