刷Leetcode算法的第十二天

序言

今天是刷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)=x2C的零值问题。其中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(xx0)+x02C

(2)然后求切线在横坐标的值:

2 x 0 ( x − x 0 ) + x 0 2 − C = 0 2x_0(x-x_0) + x_0^2 - C = 0 2x0(xx0)+x02C=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=(Cx02)/2X0+X0=C/2X01/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} 106

代码如下:

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jianafeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值