力扣【二分查找】:69. x 的平方根
- 题目描述:
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
- 算法思路:
题目要求计算一个非负整数的算数平方根且静止使用任何内置指数函数或算符,这说明我们只能通过i * i == x来寻找可能的算数平方根,
而题目限制x的范围最大为32位int的最大正数,所以i * i在int的范围内必然会溢出,导致结果出错,
又因为题目要求返回值为整数,所以x的算术平方根必然满足i * i <= x,
因此可以考虑用遍历的方式尝试从1到x的所有值,
又 x/2 == √x 当x == 4时成立,x > 4时x/2 > √2,所以可以考虑将小于4的部分和大于等于4的部分分隔开,
而且当x >= 4时√x一定位于1和x/2之间,因此不需要遍历检查到x,
先检查小于4的部分:
x == 0时√x == 0,x/2 == 0,
x == 1时√x == 1,x/2 == 0,
x == 2时√x == 1,x/2 == 1,
x == 3时√x == 1,x/2 == 1,
当x == 4时,√x == 2 == x/2,
所以在x < 4时0单独处理,x == 1,x == 2,x == 3都可以直接返回1,于是容易写出遍历的代码,
由于我们是在1 ~ x/2的范围查找算术平方根,这些数字是有序的,所以这题也可以用二分查找的方式解答,
思路相似,同样是先特别处理x < 4的部分,再二分查找x >= 4的部分
- 代码:
遍历,时间复杂度O(n)
int mySqrt(int x) {
int upper_bound = x / 2;
long long i = 1;
int result = -1;
while (i <= upper_bound) {
if (i * i > x) {
break;
}
result = i;
++i;
}
if (result != -1) {
return result;
}
return x;
}
二分查找,时间复杂度O(log (n))
int mySqrt(int x) {
if (x == 0) {
return 0;
}
int upper_bound = x / 2;
int lower_bound = 1;
while (lower_bound < upper_bound) {
int mid = lower_bound + (upper_bound - lower_bound + 1) / 2;
if (static_cast<long long>(mid) * mid > x) {
upper_bound = mid - 1;
} else {
lower_bound = mid;
}
}
return lower_bound;
}
浙公网安备 33010602011771号