力扣之x的平方根(雙指標解法思路分析最佳化)

水冗水孚發表於2023-02-01

題目描述

給你一個非負整數 x ,計算並返回 x 的 算術平方根 。

由於返回型別是整數,結果只保留 整數部分 ,小數部分將被 捨去 。

注意: 不允許使用任何內建指數函式和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

輸入: x = 4
輸出: 2

示例 2:

輸入: x = 8
輸出: 2
解釋: 8 的算術平方根是 2.82842..., 由於返回型別是整數,小數部分將被捨去。

提示:

  • 0 <= x <= 231 - 1
力扣原題目地址:https://leetcode.cn/problems/...

思路解法

分析

  • 求一個數的平方根的值,由數學常識知,那麼這個值,一定是小於等於這個數的,如:
  • 0的平方根為0,等於0
  • 1的平方根為1,等於1
  • 2的平方根約為1.414,小於2
  • 3的平方根約為1.732,小於3
  • 4的平方根為2,小於4
  • ......
  • x的平方根為m,m小於等於x
  • 所以x的平方根的值,一定是介於0和x之間的一個數

所以,我們可以使用雙指標的方式,定義兩個指標,左邊指標為0,右邊指標為x,然後透過中位數的積,去與x的值進行判斷,等於說明直接找到了;大於x那就把右側指標往左移動,即減小減一;小於x那就把左側指標往右移動,即增大加一;

如下程式碼:

實現方式一(耗時略長)

var mySqrt = function (x) {
    let left = 0 // 左側指標初始為0
    let right = x // 右側指標初始為x本身
    while (left <= right) { // 只要left小於等於right就一直執行,直至大於才停止
            // 保留整數部分,以9為例,中位數4.5保留4即可
            let middle = Math.floor((left + right) / 2) 
            if (middle * middle == x) { // 若等於則是剛好找到
                    return middle // 剛好找到則直接返回即可
            } else if (middle * middle > x) { // 若大於超過了
                    right = right - 1 // 那就減小一些
            } else if (middle * middle < x) { // 若小於為達到
                    left = left + 1 // 那就增大一些
            }
    }
    return right // 返回指標值即為平方根(四捨五入)
};

提交截圖(超出時間限制)

寫完以後,我們直接提交LeetCode,發現:超時了!!!

實際上這種寫法,對於比較小的x的值來說,是完全沒有問題的,但是對於比較大的值來說,運算需要很長時間。因為right = right - 1left = left + 1。一次減少一個,這個縮小範圍太慢。

因為LeetCode對於時間有要求,所以直接給出一個警告:超出時間限制

那麼當這個測試用例X等於2147395600時,用上述的方式,需要多長時間才能運算出來呢?如下圖:

所以到這裡,這個題目也算是解決了,但是時間過長,接下來需要做的就是最佳化,最佳化,最佳化

實現方式二(最佳化時間)

既然每次right = right - 1left = left + 1縮小範圍太小了,那我們就把縮小範圍擴大一些。直接right = middle - 1以及left = middle + 1即可,我們以中位數middle為基準,這樣就減少了很多不必要的運算。

如下程式碼:

var mySqrt = function (x) {
    let left = 0
    let right = x
    while (left <= right) {
        let middle = Math.floor((left + right) / 2)
        if (middle * middle == x) {
            return middle
        } else if (middle * middle > x) {
            right = middle - 1 // 因為中位數右側的數值肯定是不符合要求的,乾脆直接跳過
        } else if (middle * middle < x) {
            left = middle + 1 // 同上類似
        }
    }
    return right
};

這樣的話,就減少很多不必要的運算了,這樣就能夠徹底的完成任務了,如下圖:

提交截圖(搞定啦...)

總結

我們在LeetCode刷題的時候,一次不能直接寫出答案也沒事的,我們可以先寫出一個差一些的答案,然後再最佳化,最終解決問題。

即為:曲線救國的大概意思吧

以上就是筆者的力扣之x的平方根的解題思路

相關文章