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

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

虽然 测试单个整数是否是完美的正方形,比计算平方根要快, ,该范围可能很大,我也希望避免为该范围内的每个数字执行此测试。

例子:

  • intervalContainsSquare(2, 3) => false
  • intervalContainsSquare(5, 9) => false(注意:9不在此间隔之外)
  • intervalContainsSquare(9, 9) => false(此间隔为空)
  • intervalContainsSquare(4, 9) => true(在此间隔内4个)
  • intervalContainsSquare(5, 16) => true(9个间隔内9个)
  • intervalContainsSquare(1, 10) => true(1、4和9都在此间隔内)
有帮助吗?

解决方案

据我所知,计算数字是否是正方形并不比在硬情况下计算其平方根的速度更快。正确的是,您可以预先知道它不是正方形,这可能会节省您的时间。

同样,对于此问题,您可以做一个预先计算来确定SQRT(B)-SQRT(A)> = 1,这意味着A和B的分开足够远,以至于它们之间必须有一个正方形。对于某些代数,这种不平等等同于(BA-1)^2> = 4*A,或者如果您希望以更对称的形式,(AB)^2+1> = 2*(A) +b)。因此,只有一个整数产品以及一些添加和减法,就可以在没有方形根部的情况下完成此预算。

如果A和B几乎完全相同,那么您仍然可以使用将低顺序二进制数字视为预先出现的技巧,以了解它们之间没有正方形。但是他们必须如此亲密,以至于这种先例可能不值得。

如果这些预算尚无定论,那么除了其他所有人的解决方案之外,我无法想到其他任何事情,a <= ceil(sqrt(a))^2 <b。


由于有一个正确的代数问题的问题:

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)要快,因为浮点算术可以简化为整数算术,并且因为您不需要多大的牛顿的方法来确定高精度你只是要扔掉。但是实际上,如果数值库函数使用Microcode中实现的平方根,则可以更快。如果出于某种原因您没有该微码可以帮助您,那么手动编码CEIL(SQRT(a))可能值得。也许最有趣的情况是,如果A和B是无限的整数(例如一千位数字)。但是,对于普通的非观察计算机上的普通大小整数,您无法击败FPU。

其他提示

获取较低数字的平方根。如果这是一个整数,那么您就完成了。否则将数字和平方汇合。如果这小于B,那是真的。

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

为了避免A何时等于B的问题,您应该先检查该问题。因为这种情况总是是错误的。

如果您接受计算两个平方根,因为它的单调性,您的不平等现象等同于您的起点:

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

因此,如果 floor(sqrt(a)) != floor(sqrt(b)), floor(sqrt(b)) - 1 保证是这样的 n.

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

找到SQRT(A)和SQRT(B)的整体部分,例如SA和SB。

如果SA2 = a,然后输出是。

如果SB2 = b和sa = sb-1,然后输出号。

如果sa <sb输出是。

否则输出号。

您可以优化上述内容以摆脱SQRT(b)的计算(类似于Jdunkerly的答案)。

还是您也想避免计算A和B的平方根?


您可以使用类似于二进制搜索的方法完全避免完全计算正方形。

您从猜测n,n = 1开始,并计算n2

考虑一下<= n <b,您可以停止。

如果n <a <b,您的猜测n加倍。如果a <b <n,则将其接近当前 +上一个猜测的平均值。

这将是o(logb)时间。

除了Jdunkerley的Nice解决方案(+1)外,还需要进行测试和使用的可能改进 整数正方形 计算整数平方根

您为什么希望完全避免平方根?甚至在达到解决此问题的最有效方法之前,您还看到了只有2个平方根的方法。这是在O(1)时间完成的,因此在我看来,您希望做出的任何进步都将花费更多的时间来思考,而不是为您节省计算时间。我错了吗?

一种方法是使用牛顿的方法查找 整数平方根 为了 b. 。然后,您可以检查该数字是否属于该范围。我怀疑它比简单地调用平方根函数更快,但是它当然更有趣:

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;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top