1. 程式人生 > >LeetCode總結 -- 數值計算篇

LeetCode總結 -- 數值計算篇

數值計算在工業界是非常實用而且常見的具體問題, 所以在面試中出現頻率非常高, 幾乎可以說是必考題目。 LeetCode中關於數值運算的有以下題目: 
Palindrome Number
Reverse Integer
Sqrt(x)
Pow(x, n)
Divide Two Integers
Max Points on a Line
在LeetCode中, 關於數值運算的題目分為三種類型, 下面將進行一一講解。 

第一種型別是最簡單的, 就是對整數進行直接操作, 一般來說就是逐位操作, 比如反轉, 比較等。 LeetCode中這類題目有Palindrome NumberReverse Integer。 這類題目通常思路很清晰, 要注意的點就是對於邊界情況的考慮, 對於數值而言, 主要問題是對於越界情況的考慮。 實際上越界問題是貫穿於所有數值計算題目的常見問題, 下面大多問題都會強調這點。 

Palindrome Number中因為只是進行判斷, 並不需要修改數字, 所以沒有越界問題。 思路比較簡單, 就是每次取出最高位和最低位進行比較, 直到相遇或者出現違背條件(也就是不相等)即可返回。 對於Reverse Integer因為需要對數字進行反轉, 所以需要注意反轉後的數字可能會越界。 對於越界一般都是兩種處理方法, 一種是返回最大(或者最小)數字, 一種則是丟擲異常, 這個可以跟面試官討論, 一般來說, 面試只要簡單的返回最大最小或者dummy數字就可以了, 但是處理和檢查這種corner case(也就是越界)的想法一定要有和跟面試官討論。 

第二種題型是算術運算的題目, 比如乘除法, 階乘, 開方等, LeetCode中這類題目有
Sqrt(x), Pow(x, n)Divide Two Integers。 這種題目有時候看似複雜, 其實還是有幾個比較通用的解法的, 下面主要介紹三種方法: 
(1)二分法。 二分法是數值計算中很常用和易懂的方法。 基本思路是對於所求運算進行對半切割, 有時是排除一半, 有時則是得到可重複使用的歷史資料。Sqrt(x)就是屬於每次排除一半的型別, 對於要求的開方數字進行猜測, 如果大於目標, 則切去大的一半, 否則切去大的一半, 原理跟二分查詢是一樣的。Pow(x, n)則是屬於重複利用資料的型別, 因為x的n次方實際上是兩個x的n/2次方相乘, 所以我們只需要遞迴一次求出當前x的當前指數的1/2次方, 然後兩個相乘就可以最後結果。 二分法很明顯都是每次解決一半, 所以時間複雜度通常是O(logn)量級的。 

(2)牛頓法。 這種方法可以說主要是數學方法, 不瞭解原理的朋友可以先看看牛頓法-維基百科。 Sqrt(x)就非常適合用牛頓法來解決, 因為它的遞推式中的項都比較簡單。 Pow(x, n)當然原理上也可以用牛頓法解答, 但是因為他的遞推式中有項是進行x的開n次方的, 這個計算代價也是相當大的, 如果為了求x的n次方而去每一步求開n次方就沒有太大實際意義了, 所以對於這種題我們一般不用牛頓法。 
(3)位移法。 這種方法主要基於任何一個整數可以表示成以2的冪為底的一組基的線性組合, 對一個整數進行位數次迭代求解, 因為複雜度是位數的數量, 所以也跟二分法一樣是O(logn)量級的。 Pow(x, n)Divide Two Integers就是比較典型可以用這種方法解決的題目。 對於Pow(x, n)可以把n分解成位, 每次左移恰好是當前數的平方, 所以進行位數次迭代後即可以得到結果, 程式碼中很大的篇幅都是在處理越界問題, 而關於逐位迭代程式碼卻很簡短。 Divide Two Integers同樣把結果分解成位, 每次對除數進行位移並且減去對應的除數來確定每一位上的結果。 這種方法可能理解起來沒有二分法那麼直觀, 還是要消化一下哈。 

第三種題目是解析幾何的題目, 一般來說解析幾何題目的模型都比較複雜, 而且實現細節比較多, 在面試中並不常見, LeetCode中也只有Max Points on a Line是屬於這種題型。 這種題目沒有什麼通法, 主要就是要理清數學和幾何模型, 比如Max Points on a Line中主要是理解判斷點在直線的判斷公式, 然後進行迭代實現。 實現細節還是比較多的, 需要對一些邊界情況仔細考慮。 

這篇總結主要列舉了LeetCode中關於數值計算的題目, 介紹了這類問題的主要考點(比如越界判斷)和常用的幾種實用方法, 總體感覺這類問題是在面試中比較難很快寫對的題目, 因為有一些邊界情況和數值實現的細節。 因為出現頻率很高, 還是需要對這類題目重點練習哈。