关注微信公众号“酸痛鱼”,获得更多最新最全的文章。
本文中所涉及的代码,在未特殊声明的情况下,都是基于Python3程序设计语言编写的。
建议您在PC浏览器中阅读本文。
如果您未掌握知识提要中的内容,建议您先掌握这些内容之后再阅读本文。
知识提要
1、math库
2、int取整操作
3、牛顿迭代(未掌握不影响对本文的理解)
4、二分查找(未掌握不影响对本方的理解)
0
问题描述
给定一个非负整数x,求x的正数平方根r。要求:只保留正数根的整数部分。
例如:
当x = 2时,r = 1。(2的平方根约为1.414)
当x = 4时,r = 2。(4的平方根为2)
当x = 8时,r = 2。(8的平方根约为2.828)
为了表述方便,在本文中,我们直接将“正数平方根”称为“平方根”,在无歧义的情况下,会直接称为r。
1
系统函数法
大部分编程语言都提供了丰富的数值操作的系统函数,例如向上取整ceil,向下取整floor,求平方根sqrt,等等。Python当然也不例外。对于本章题目,最简单和最高效的解法,就是利用系统函数,先求x的平方根,再向下取整。
import math
def mySqrt(x):
# 求x的根,并向下取整,相当于math.floor(math.sqrt(x))
return int(math.sqrt(x))
如果这是一个竞赛题目,而没有禁止使用系统函数,那么如上的代码绝对是最优解。出于“学术”讨论和拓展学习的目的,我们将在本文中重点讨论其它的解题思路。
2
暴力破解法
对于任意大于1的正整数x,它的平方根一定不大于x的一半。利用这个特点,我们可以从x/2开始,不停地向左探索,直到到第一次找到一个数r,满足r的平方不大于x,此时,r就是我们的解。
def mySqrt(x):
if x <= 1: return x
r = x // 2
while r > 1:
if r * r <= x:
return r
else:
r -= 1
return 1
不得不提的是,这种解法是存在严重的效率问题。当x值为1亿的时候,在我的计算机上,大概花了4秒钟的运行时间。如果你在比赛中使用这种解法,极有可能因为运行时间过长而被判定为解题失败。
3
牛顿迭代法
在这里,我将假设你知道什么是牛顿迭代。不过如果你只是专注于题目本身的求解,你只需要知道牛顿迭代怎么用就行了,可以不必了解它的原理。
假设r{n}表示第n次迭代的值,那么迭代公式为:
r{n+1}= (r{n} + x/r{n})/2
由于我们求解的精度为保留小数点0位,即取整,所以我们只需要迭代到r{n+1}和r{n}的整数部分相等时即可。此时r{n+1}的整数部分就是我们的解。
def mySqrt(x):
r = 1
n = 0
while int(r) != int(n):
n = r
r = (n + x / n) / 2
return int(r)
4
二分查找法
给定一个整数q,在升序的有序整数数列A中,找到q的位置。我们用A(i)表示A的第i个元素,用A(i, j)表示A中第i个到第个j的元素集合。假如A的长度为len,则A的最大下标e=len-1。如果q是A中元素,那么q一定落在A(0,e)中。我们可以通以下的步骤进行有限次的迭代,得到结果:
A、令s = 0,e = len - 1
B、如果s > e;跳转到G
C、令m = (s + e) / 2
D、如果A(m) < q,q的范围缩小为A(m + 1, e);可令s = m + 1,跳转到B;
E、如果A(m) > q,q的范围缩小为A(s, m - 1);可令e = m - 1,跳转到B;
F、如果A(m) == q,那么m就是q在A中的位置;查找结束
G、q不在数组A中。查找结束
对于我们的题目,也就是求解x平方根r的题目来说,模型退化了,A相当于整数数组[1,2,3,……,x],而且一定有解。我们还需要稍微改造一下,就是在A(1, x)中,找到A(m),满足A(m)^2 <= x < A(m+1)^2。事实上,就是在1到x中,找到m,满足m^2 <= x < (m+1)^2。
def mySqrt(x):
if x <= 1: return x
s, e = 1, x # A
while s <= e: # B
m = (s + e) // 2 # C
val1, val2 = m * m, (m + 1) * (m + 1)
if val1 <= x < val2: # F
return m
if val1 < x: # D
s = m + 1
else: # E
e = m - 1
return -1 # G●微信 扫码关注会变帅哦
酸痛鱼,与你分享快乐的代码