一系列整数是否包含至少一个完美的正方形?

时间:2010-06-29 12:25:45

标签: algorithm math integer square-root

给定两个整数ab,是否有一种有效的方法来测试是否存在n的另一个整数a ≤ n2 < b

我不需要知道n,只知道是否存在至少一个这样的n,所以我希望避免计算任何数字的平方根间隔。

虽然testing whether an individual integer is a perfect square is faster than computing the square root,但范围可能很大,我也希望避免对范围内的每个数字执行此测试。

示例:

  • intervalContainsSquare(2, 3) =&gt;假
  • intervalContainsSquare(5, 9) =&gt; false(注意:9超出此间隔)
  • intervalContainsSquare(9, 9) =&gt; false(此间隔为空)
  • intervalContainsSquare(4, 9) =&gt; true(4在此区间内)
  • intervalContainsSquare(5, 16) =&gt; true(9在此区间内)
  • intervalContainsSquare(1, 10) =&gt; true(1,4和9都在此区间内)

8 个答案:

答案 0 :(得分:26)

据我所知,计算一个数字是否为正方形并不比在困难情况下计算其平方根更快。这是真的,你可以做一个预先计算,知道它不是一个正方形,这可能会节省你平均的时间。

同样对于这个问题,你可以进行预计算以确定sqrt(b)-sqrt(a)&gt; = 1,这意味着a和b相距足够远,它们之间必须有一个正方形。对于一些代数,这个不等式等价于(ba-1)^ 2> = 4 * a的条件,或者如果你想要它以更对称的形式,那么(ab)^ 2 + 1> = 2 * (A + b)。所以这个预计算可以在没有平方根的情况下完成,只需要一个整数乘积和一些加法和减法。

如果a和b几乎完全相同,那么你仍然可以使用查看低阶二进制数字作为预计算的技巧来知道它们之间没有正方形。但它们必须如此接近,以至于这种预计算可能不值得。

如果这些预先计算是不确定的,那么除了其他人的解决方案之外,我无法想到任何其他解决方案,&lt; = ceil(sqrt(a))^ 2&lt;湾


由于存在正确代数的问题:

sqrt(b)-sqrt(a) >= 1
sqrt(b) >= 1+sqrt(a)
b >= 1+2*sqrt(a)+a
b-a-1 >= 2*sqrt(a)
(b-a-1)^2 >= 4*a

另外:通常当a是一个大数字时,你可以使用牛顿方法计算sqrt(a),或者使用查找表,然后使用几个牛顿方法步骤。原则上计算ceil(sqrt(a))比sqrt(a)更快,因为浮点运算可以简化为整数运算,并且因为你不需要那么多Newton的方法步骤来确定高精度你只是要扔掉。但实际上,如果使用微码中实现的平方根,数值库函数可以快得多。如果由于某种原因你没有那个微代码来帮助你,那么手动编码ceil(sqrt(a))可能是值得的。也许最有趣的情况是如果a和b是无界整数(比如,千位数)。但是对于普通的非过时计算机上的普通大小的整数,你无法击败FPU。

答案 1 :(得分:18)

获取较低数字的平方根。如果这是一个整数,那么你就完成了。 否则将数字四舍五入。如果这小于b那么它就是真的。

您只需要以这种方式计算一个平方根。

为了避免a等于b的问题,你应该先检查一下。因为这种情况总是错误的。

答案 2 :(得分:4)

如果你接受计算两个平方根,由于它的单调性,你有这个不等式,这相当于你的起始点:

sqrt(a) <= n < sqrt(b)

因此,如果floor(sqrt(a)) != floor(sqrt(b)),则floor(sqrt(b)) - 1保证为n

答案 3 :(得分:4)

  1. 获取较低数字的平方根并将其四舍五入
  2. 获取较高数字的平方根并将其向下舍入
  3. 如果1低于或等于2,则会有一个完美的正方形

答案 4 :(得分:2)

找到sqrt(a)和sqrt(b)的组成部分,比如sa和sb。

如果sa 2 = a,则输出yes。

如果sb 2 = b且sa = sb-1,则输出编号

如果sa&lt; sb输出是。

其他输出编号

你可以优化上面的方法来摆脱sqrt(b)的计算(类似于JDunkerly的回答)。

或者你是否想避免计算a和b的平方根?


您可以通过使用类似于二分搜索的方法来完全避免计算平方根。

首先猜测n,n = 1并计算n 2

考虑是否&lt; = n&lt; b,你可以停下来。

如果n < a&lt; b,你加倍猜测n。 如果a&lt; b&lt; n,你使它接近当前+之前猜测的平均值。

这将是O(logb)时间。

答案 5 :(得分:0)

一种方法是使用牛顿方法查找b的{​​{3}}。然后,您可以检查该数字是否在该范围内。我怀疑它比简单地调用平方根函数更快,但它肯定更有趣:

int main( int argc, char* argv[] )
{
    int a, b;
    double xk=0, xk1;
    int root;
    int iter=0;
    a = atoi( argv[1] );
    b = atoi( argv[2] );

    xk1 = b / 32 + 1;  // +1 to ensure > 0
    xk1 = b;
    while( fabs( xk1 - xk ) >= .5 ) {
        xk = xk1;
        xk1 = ( xk + b / xk ) / 2.;
        printf( "%d) xk = %f\n", ++iter, xk1 );
    }

    root = (int)xk1;

    // If b is a perfect square, then this finds that root, so it also
    // needs to check if (n-1)^2 falls in the range.
    // And this does a lot more multiplications than it needs
    if ( root*root >= a && root*root < b ||
         (root-1)*(root-1) >= a && (root-1)*(root-1) < b )
        printf( "Contains perfect square\n" );
    else
        printf( "Does not contain perfect square\n" );

    return 1;
}

答案 6 :(得分:0)

除了JDunkerley的优秀解决方案(+1)之外,还有可能需要测试的改进并使用integer square roots来计算整数平方根

答案 7 :(得分:0)

为什么你希望完全避免平方根?甚至在你以最有效的方式解决这个问题之前,你已经看到了只需要2平方根的方法。这是在O(1)时间内完成的,所以在我看来,你可能希望做出的任何改进都需要花费更多时间来思考,而不是节省计算时间。我错了吗?