【问题标题】:Implement floored square root using binary search使用二分搜索实现底平方根
【发布时间】:2020-06-27 20:09:23
【问题描述】:

好的,所以我已经研究了一段时间,我知道我的逻辑是正确的,但是,我似乎无法生成正确的正数的底平方根。

    public int mySqrt(int x) {
        if(x < 2) return x;
    
        double lowerBound = 0.0, upperBound = x, midPoint = 0.0;
        while(lowerBound <= upperBound) {

            midPoint = lowerBound + (upperBound - lowerBound) / 2;
            double square = Math.pow(midPoint, 2);

            if(Double.compare(square, x) < 0) lowerBound = midPoint + 1;
            else if(Double.compare(square, x) > 0) upperBound = midPoint - 1;
            else return (int) midPoint;
        }

        return (int) midPoint;
    }

例如,我失败的一个测试用例是针对x = 2:它应该返回 1 但我返回 2。这没有意义,因为我显然先取了一个 midPoint。向左或向右的逻辑是错误的吗?

【问题讨论】:

  • @Michael 因为我返回的是真正平方根的取底结果,所以 sqrt(2) = 1.414... 所以我返回 1。

标签: java algorithm binary-search


【解决方案1】:

由于您正在对双精度值执行二进制搜索,因此您应该设置一个容差,并在高低之间的差异低于该容差时停止循环(标准容差通常为1e-6)。您还应该设置low = midhigh = mid 而不是加或减一,因为您不是对int 值进行二进制搜索。请参阅下面的代码here

private static final double TOLERANCE = 1e-10;
public int mySqrt(int x) {
    if (x < 2)
        return x;
    double lowerBound = 0.0, upperBound = x, midPoint = 0.0;
    while (upperBound - lowerBound >= TOLERANCE) {
        midPoint = lowerBound + (upperBound - lowerBound) / 2;
        double square = Math.pow(midPoint, 2);
        if (Double.compare(square, x) < 0)
            lowerBound = midPoint;
        else if (Double.compare(square, x) > 0)
            upperBound = midPoint;
        else
            return (int) midPoint;
    }
    return (int) midPoint;
}

如果您从没想过需要更高的精度,您可以使用ints 进行二进制搜索。请参阅下面的代码here

public int mySqrt(int x) {
    if (x < 2)
        return x;
    int low = 0, high = x;
    while (low < high - 1) {
        final int mid = low + high >>> 1;
        if (mid <= x / mid) {
            low = mid;
        } else {
            high = mid;
        }
    }
    return low;
}

【讨论】:

    【解决方案2】:

    您不应该为此使用任何 double 数学。您必须进行更多迭代才能获得准确的double 值,然后您就将其丢弃。您应该使用这样的整数解决方案:

    int mySqrt(int x) {
        if (x<2) {
            return x;
        }
        int minval=1, maxval=x/2;
    
        while(minval < maxval) {
            // rounding up here means we never choose minval
            int test = minval + (maxval - minval + 1)/2;
            // testing this way avoids a multiply that could overflow
            if (x/test < test) {
                //too high
                maxval = test-1;
            } else {
                //not too high
                minval = test;
            }
        }
        return minval;
    }
    

    【讨论】:

      【解决方案3】:

      由于输入是int,结果是int,这根本不应该涉及浮点运算。

      public static int mySqrt(int i) {
          if (i < 2)
              return i;
          int lower = 0, upper = i;
          do {
              int guess = lower + (upper - lower) / 2;
              if(guess <= i / guess) {
                  lower = guess;
              } else {
                  upper = guess;
              }
          } while ((upper - lower) > 1);
          return lower;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-15
        • 2020-09-08
        • 2015-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多