leeCode69_x的平方根

一、题目内容

实现int sqrt(int x)函数。
计算并返回x的平方根,其中x是非负整数。
由于返回类型是整数,结果只保留整数部分,小数部分将被舍去。

示例1
输入:4

输出:2

示例2
输入:8

输出:2

说明:8的平方根是2.82842…由于返回类型是整数,小数部分将被舍去。

二、题目分析

使用二分法来完成平方根还是比较容易被想到的,在有限的“区间”中,每次通过筛选一半的元
素,到最终只剩下一个数(收敛),这个数就是题目要求的取整的平方根整数。

根据之前说过的二分法模板,要使用二分法,我们当然要找到Left,Right,Mid,那在这里,Mid 自然被作为最终我们要找的平方根的值(不像上一道题,Mid是作为速度,不太容易被想到),而 Left 和Right,我们采用 1 和x/2。

Left 设置为 1 比较容易理解,因为我们可以直接处理掉 x 为 0 的情况(当然,也可以把 Left 初始化为2,然后我们额外处理 0 和 1 的情况,我之前说过,二分法一万个人有一万种写法,只要能解释清楚,那就是你自己的)。但是为什么 Right 是 x/2 呢?

我们看一下下面这些数的值:
在这里插入图片描述
很容易观察出,当 x>2 时,它的整数平方根一定小于等于 x/2 。即有 0 < 整数平方根 <= x/2。所以我们的问题转化为在 [0,x/2] 中找一个特定值,满足二分查找的条件。(当然,如果没有想到使用 x/2 作为Right 而 直接使用 x ,其实也是可以的)

剩下的逻辑就很简单了,我们不停缩小mid的范围,如果最终平方大于x就放回它前面一个值,否则就正常返回,直到两边的边界完全收敛。

三、代码实现

public class Solution {
    
    
	public int mysqrt(int x) {
    
    
		if(x == 0) return 0;
		long left = 1;
		long right = x / 2;
		while(left < right) {
    
    
			long mid = (right + left) / 2 + 1;
			if(mid > x / mid) {
    
    
				right = mid - 1;
			} else {
    
    
				left = mid;
			}
		}
		return (int)left;
	}
}

上面的代码,有三处需要进行讲解:

  1. 第一,就是这里将 left 和 right 都设置为了 long,这是因为担心超出界限。同时,也正是因为设置为了 long,所以后面我可以直接使用 right left,而不用担心报错。
  2. 第二,还是这行代码,大家肯定会疑惑,为什么我要在 (right left)/ 2 后面再加1。这其实是一种技巧,一般人我不告诉他。因为在面试的时候,我们往往需要快速写出freebug 的代码,但是如果遇到二分的题目,你很可能会不停的纠结 mid 到底如何设置,是左边界还是右边界。其实,面试官大多时候,并不需要你写出一个非常非常标准的二分,找到绝对的中值。
  3. 第三,这点本来不需要额外说明的,正是在第二的基础上,我们通过不停的缩小搜索空间,最终left 就变成我们要找的 mid 值,所以直接返回 left 就可以了。

猜你喜欢

转载自blog.csdn.net/qq_44880095/article/details/113193495
今日推荐