刷题笔记
69. Sqrt(x)
题目
Given a non-negative integer x, compute and return the square root of x.
Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned.
思路
- 用二分法思想,开跟的数一定在1和x之间(除0之外),那么这是一个在1和x之间寻找目标值的二分法查找问题。
代码实现
class Solution {
public int mySqrt(int x) {
int left = 0, right = x;
if (x == 0) return 0;
if (x == 1) return 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (mid == x / mid) return mid;
else if (mid < x / mid) {
if ((mid + 1) > x /(mid + 1)) return mid;
else left = mid + 1;
} else {
right = mid - 1;
}
}
return 0;
}
}
这个思路下跑出来的结果很烂,事实证明这个code确实写的稀烂。
下面看看热评中的解法:
class Solution {
public int mySqrt(int x) {
int i = 1;
int j = x;
int ans = 0;
while (i <=j){
int mid = i + (j-i)/2;
// upper bound的形式,因为我们要找的ans要是最接近于x的最大的数,利用upper bound
if (mid <= x/mid){
i = mid +1;
ans = mid;
}
else
j = mid-1;
}
return ans;
}
}
我仿照热评重新写的写法:
class Solution {
public int mySqrt(int x) {
int left = 1, right = x;
while (left <= right){
int mid = left + (right - left) / 2;
if (mid <= x / mid) left = mid + 1;
else right = mid - 1;
}
return --left;
}
}
这样的效果好很多
分析这种写法:
- 首先注意到,left并不是取到0而是取到1,这样当x = 0的时候,不进循环直接return 0;而当x = 1,会循环一次,第一次得到left = 2,然后return1。这一点很巧妙。
- 然偶当其他情况,要跳出循环的必要条件只有left和right错位,而错位的条件是二者先紧邻,相等,然后错位。紧邻的时候,如果其中left = target,那么left先+1,left和right相等,然后right - 1,跳出循环,返回left - 1,答案正确;如果right = target,那么left依然+1,然后left再+1,然后返回left-1,答案正确;如果target在left和right之间,那么mid = left,left + 1,然后right - 1,返回left - 1,答案正确。
- 综上,这种解法很巧妙的在所有情况下都返回正确值。