思路1:二分法。

初始low=1, high的初始化有讲究:
若x大于4,high初始化为x/2; 若x<=4,high初始化为x. 至少这样可加速查找过程。(证明很简单,见下图)
  • 若mid*mid <= x,接着判断
  •  (1)若(mid+1)^2>x,则返回mid;
    
  •  (2)否则在右半区间查找,low=mid+1;
    
  • 若mid*mid > x,在右半区间查找,high=mid-1;
  • 另外需要注意运算避免溢出 alt

复杂度

空间复杂度 O(1),时间复杂度 O(logx)

代码(JAVA)

public class Solution {
	public int sqrt (int x) {//二分法
        if(x==0||x==1) return x;//题中告诉我们x的范围: 0 <= x < 2^31-1
        int low=1,high=x;
        if(x>4) high=high>>1;//x大于4时,根号x小于x/2
        int mid=0;
        while(low<=high) {
        	mid=low+((high-low)>>1);//注意,加法运算符优先级比移位运算符优先级高,移位运算符外面需要加括号
        	if(mid<=x/mid) {
        		if(mid+1>x/(mid+1)) return mid;
        		else low=mid+1;
        		}
        	else high=mid-1;
        	}
        return 0;
    }
}

思路2:牛顿迭代法(Newton-Raphson method)。

这里先引用一些介绍,不熟悉牛顿迭代公式的小伙伴可以看一下,熟悉的可跳过。
产生背景:

alt

牛顿迭代公式:

alt

利用迭代算法解决问题,需要做好以下三个方面的工作:
一、确定迭代变量

在可以用迭代算法解决的问题中,至少存在一个可直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。

二、建立迭代关系式

所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。

三、对迭代过程进行控制

在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。 对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析得出可用来结束迭代过程的条件。

对应此题,我给大家做了推导过程,迭代公式由泰勒展开前两项得到,不难得到。
需要特别关注最后的推导结果

alt

代码(JAVA)

public class Solution {
	public int sqrt (int x) {//牛顿迭代法
        if(x==0||x==1) return x;//题中告诉我们x的范围: 0 <= x < 2^31-1
		long X0=x;//使用int进行加法运算可能溢出,所以采用long型
		long X1=0;//下一个迭代变量,为了方便理解,也可只使用X0
		while(X0>x/X0) {//X0^2>x循环
			X1=(X0+x/X0)>>1;//由迭代公式得,采用右移1位操作代替除以2,运算更快
			X0=X1;//把下一个迭代变量赋给X0,统一操作,方便继续处理
		}
		return (int)X0;//返回值类型为int,因此需要做强制类型转换
    }
}

:最后相信大家把这道题拿捏到手了吧