1. 程式人生 > >LeetCode演算法題-Sqrt(Java實現)

LeetCode演算法題-Sqrt(Java實現)

這是悅樂書的第158次更新,第160篇原創

01 看題和準備

今天介紹的是LeetCode演算法題中Easy級別的第17題(順位題號是69)。 計算並返回x的平方根,其中x保證為非負整數。 由於返回型別是整數,因此將截斷十進位制數字,並僅返回結果的整數部分。例如:

輸入:4
輸出:2

輸入:8
輸出:2
說明:8的平方根是2.82842 ...,從2以後小數部分被截斷,返回2

本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。

02 第一種解法

使用二分法來算平方根。

特殊情況一:在求中間數時,需要考慮整型溢位的情況。因為在計算中間數時,習慣性很容易就寫出mid = (right+left)/2,但是left+right的值如果溢位,那麼整個計算都是失真的。此時,我們就需要做下替換,用減法替代加法:

right/2 + left/2
right/2 - left/2 + left
(right-left)/2 + left

特殊情況二:在判斷中間數的平方是否等於傳入的引數時,習慣性就寫出 mid*mid == x,這其實也是存在溢位風險的,也可以變換下,做除法,即 x/mid == mid。

特殊情況三:傳入的引數小於等於0的時候,直接返回0即可。

二分法來取平方根,低位取1,高位是x本身,如果低位小於等於高位,就進入迴圈求得兩者中間數,做除法比較是否相等,相等則返回中間數,如果高位除以中間數大於中間數,則低位等於中間數向前加1,如果高位除以中間數小於中間數,則高位等於中間數向後減1。直到低位大於高位,結束迴圈,返回高位。

public int mySqrt(int x) {
    if (x < 1)
        return 0;
    int low = 1;
    int high = x;
    while (low <= high) {
        int mid = (high - low) / 2 + low;
        if (x / mid == mid)
            return mid;
        if (x / mid > mid)
            low = mid + 1;
        if (x / mid < mid)
            high = mid - 1;
    }
    return high;
}

03 第二種解法

直接使用Math自身的sqrt()方法,如果面試時遇到此題,還是以上面的解法或者下面的第三種為好。

public int mySqrt2(int x) {
    return (int) Math.sqrt(x);
}

04 第三種解法

利用牛頓迭代法計算開平方根,在此不過多描述,會單獨抽時間來寫這個經典的求平方根解法。

public int mySqrt3(int x) {
    double flag = 0.1d;
    if (x <= 0) {
        return 0;
    }
    double val = x;
    double last;
    do {
        last = val;
        val = (val + x / val) / 2;
    } while (val - last > flag || val - last < -flag);
    return (int) val;
}

05 測試用例和結果

對比上述三種解法,使用了一些資料做了測試,並記錄了演算法花費的時間。

public static void main(String[] args) {
    Easy_069_Sqrt instance = new Easy_069_Sqrt();
    int arg = 2;
    long start = System.nanoTime();
    int result = instance.mySqrt(arg);
    long end = System.nanoTime();
    System.out.println("mySqrt()---輸入:" + arg + " , 輸出:" + result + " , 用時:" + ((end - start) / 1000) + "微秒");
    System.out.println("-----------------------------------------------");
    long start2 = System.nanoTime();
    int result2 = instance.mySqrt2(arg);
    long end2 = System.nanoTime();
    System.out.println("mySqrt2()---輸入:" + arg + " , 輸出:" + result2 + " , 用時:" + ((end2 - start2) / 1000) + "微秒");
    System.out.println("-----------------------------------------------");
    long start3 = System.nanoTime();
    int result3 = instance.mySqrt3(arg);
    long end3 = System.nanoTime();
    System.out.println("mySqrt3()---輸入:" + arg + " , 輸出:" + result3 + " , 用時:" + ((end3 - start3) / 1000) + "微秒");
}

測試結果如下

mySqrt()---輸入:3600 , 輸出:60 , 用時:4微秒
-----------------------------------------------
mySqrt2()---輸入:3600 , 輸出:60 , 用時:20微秒
-----------------------------------------------
mySqrt3()---輸入:3600 , 輸出:60 , 用時:5微秒

06 小結

方法1和方法3運算速度還是較快的,Math類的sqrt方法與之對比還是稍遜一些。以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!