關注微信公衆号“酸痛魚”,獲得更多最新最全的文章。
本文中所涉及的代碼,在未特殊聲明的情況下,都是基于Python3程式設計語言編寫的。
建議您在PC浏覽器中閱讀本文。
如果您未掌握知識提要中的内容,建議您先掌握這些内容之後再閱讀本文。
知識提要
1、math庫
2、int取整操作
3、牛頓疊代(未掌握不影響對本文的了解)
4、二分查找(未掌握不影響對本方的了解)
問題描述
給定一個非負整數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●微信 掃碼關注會變帥哦
酸痛魚,與你分享快樂的代碼