每日一題,防止癡呆 = =
一、題目大意
實現 int sqrt(int x) 函數。
計算並返回 x 的平方根,其中 x 是非負整數。
由於返回類型是整數,結果只保留整數的部分,小數部分將被捨去。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/sqrtx
二、題目思路以及AC代碼
這題確實思路很多,但是確實沒有想到可以用數值計算的方法求解 = =。
思路一
首先比較有意思的是,可以直接用STL的sqrt方法通過,雖然這樣通過的也沒什麼用,畢竟不是考你調庫。
思路二
可以直接暴力,即遍歷1~x的所有整數,遍歷元素爲i,如果ii等於x,那麼結果就是i,如果沒有遇到相等的,但第一次遇到ii > x,那麼 i-1 就是結果。
思路三
既然可以暴力遍歷,由於這題又有順序,就也可以二分,思路同上,需要注意的是,可能mid*mid並不等於x,小於x,但是由於是取整,所以最後的結果也可能就是這個數,此時在最後的時候,要判斷一下是取l還是l-1。
思路四
前面三個都是比較基礎的思路,哦,第一個不算思路,下面就是看題解看到的比較有意思的了,首先一個是利用其餘的運算來代替根號運算。
如上,就可以將根號運算,轉換爲指數和對數運算了,但由於精度問題,最後要判斷一下,結果是res還是res+1。
思路五
就是數值計算的方法了,利用迭代的方法,求取函數零點。這裏使用的是牛頓法,具體這裏就不介紹了,主要是根據梯度去不斷靠近零點,但要注意初始值的選取,因爲選取不好的話,可能會收斂到另一個零點。
下面給出思路三和思路五的AC代碼,其實一開始暴力也寫了,不過丟了 = =。
思路三,二分
typedef long long ll;
class Solution {
public:
int mySqrt(int x) {
int res = 0;
int l = 0, r = x;
while (l < r) {
ll mid = (l + r) >> 1;
if (mid*mid == x) {
return mid;
}
if (mid*mid < x) l = mid + 1;
if (mid*mid > x) r = mid - 1;
}
if (l*l > x) res = l-1;
else res = l;
return res;
}
};
思路五,牛頓法
class Solution {
public:
int mySqrt(int x) {
if (!x) return 0;
double res = x;
double last = res;
double epsilon = 1e-7;
while (1) {
res = (res + x/res) / 2;
if (abs(res - last) <= epsilon) {
break;
}
last = res;
}
return res;
}
};
如果有問題,歡迎大家指正!!!