编程语言应用

首页 » 常识 » 诊断 » 如何在CC中实现整数平方根
TUhjnbcbe - 2023/4/30 21:21:00
北京中科刘云涛 http://hunan.ifeng.com/a/20170705/5797804_0.shtml

问题:为intsqrt(intx)实现整数平方根

有很多方法可以计算整数平方根。但是如果你不打扰,你总是可以欺骗编译器(在线判断),但不要在你的面试中这样做!

作弊方式:

好吧,大多数编程语言都有用于浮点数(单精度或双精度)的sqrt,我们可以简单地编写:

#includemath.h

classSolution{

public:

intsqrt(intx){

//addstd::namespacetodistinguishfromcurrentsqrt()

return(int)std::sqrt(x);

}

};

或者

publicclassSolution{

publicintsqrt(intx){

return(int)Math.sqrt(x);

}

}

或者

#includemath.h

classSolution{

public:

intsqrt(intx){

return(int)pow(x,0.5);

}

};

穷举搜索:

人们可能会很快想出一个蛮力搜索。我们只需要尝试从1开始的数字,直到这个数字的平方大于输出。

#includemath.h

typedefunsignedlonglongULONG;

classSolution{

public:

intsqrt(intx){

ULONGa=1;

while(a*a=x)a++;

return--a;

}

}

请注意,我们定义了一个unsignedlonglong类型来保存a*a的中间结果,这样结果就不会溢出(对于32位整数来说太大了)。

好吧,以上似乎不太可能在网上判断中接受。但令人惊讶的是,这是一个公认的解决方案。这是为什么?的int类型是32位有符号整数,其给出的最大值2^31-1=。这个的平方根只是.9,这意味着最多次迭代,我们有正确的整数根。这在现代处理器中是微不足道的,可以在百万秒内完成。

改进:

我们注意到a*a很费计算资源,如何摆脱它?

因此,我们只需将2添加到变量delta并将其添加到当前变量a即可得到a+1的平方。

#includemath.h

typedefunsignedlonglongULONG;

classSolution{

public:

intsqrt(intx){

ULONGa=1;

ULONGdelta=3;

while(a=x){

a+=delta;//(a+1)^2

delta+=2;

}

returndelta/2-1;

}

}

上述改进去除了乘法并仅使用加法,这通常在一些时间不是关键问题的PC板中实现。

二分查找:

上面的算法复杂度是O(n)并且当给定的整数很大时它仍然很慢。二分查找可以将其缩短为

二分搜索是最重要的算法之一,为了使其工作,它需要连续的搜索空间(例如数字排序)

在整数平方根的域中,我们可以很容易地发现:

小于

任何给定的非负整数。

#includemath.h

typedefunsignedlonglongULONG;

classSolution{

public:

intsqrt(intx){

ULONGl=0,r=x;

while(l=r){

ULONGmid=l+(r-l)/2;//(l+r)/2;

ULONGmidmid=mid*mid;

//checkifxfallsinto[mid^2,(mid+1)^2)

if((midmid=x)(x(mid+1)*(mid+1)))returnmid;

if(midmidx){

r=mid-1;

}else{

l=mid+1;

}

}

}

}

使用二分搜索,每次迭代都会将搜索空间缩小到一半。的中期=(L+R)/2可能溢出所以我们可以使用中间=1+(R-1)/2来完成相同的事情。

牛顿法:

二分搜索是一个很大的改进,但找到解决方案仍然太慢。现代处理器实现了硬件平方根算法,其中大部分基于牛顿方程:

正如我们所看到的,随着牛顿方程的每次迭代,我们找到了更接近的根

我们有初步的猜测

例如,

牛顿法收敛很快,被认为非常有效。

#includemath.h

typedefunsignedlonglongULONG;

classSolution{

public:

intsqrt_newton(intx){

if(x==0)returnx;

doubledividend=x;

doubleval=x;

doublelast;

do{

last=val;

val=(val+dividend/val)*0.5;

}while(abs(val-last)1e-9);//precision

return(int)val;

}

}

我们

用最后一次检查当前迭代

,如果差异小于例如1e-9(EPSILON),那么我们认为我们已经获得了所需的精度。

另一个类似的问题是检查给定的整数是否是有效的完美平方。

1
查看完整版本: 如何在CC中实现整数平方根