如何优化此解决方案以避免超过时间限制?

时间:2020-04-04 21:14:40

标签: java algorithm optimization

这是我对this问题的解决方案:

给出一个表示为(半径,x_center,y_center)的圆和一个 轴对齐的矩形表示为(x1,y1,x2,y2),其中(x1,y1) 是左下角的坐标,而(x2,y2)是 矩形右上角的坐标。

如果圆形和矩形重叠,则返回True 返回False。

换句话说,检查是否存在任何点(xi,yi)使得 同时属于圆形和矩形。

class Solution {
    public boolean checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) {

        for(int i=x1; i<=x2; ){
            for(int j=y1; j<=y2; ){                
                System.out.println((Math.pow(i-x_center, 2) +" "+ Math.pow(j-y_center, 2))+" "+Math.pow(radius, 2));
                System.out.println(i+" "+j);
                if((Math.pow(i-x_center, 2)+Math.pow(j-y_center, 2))<=Math.pow(radius, 2)){
                    return true;
                }
                j += 1;
            }
            i += 1;
        }

        return false;
    }
}

我非常相信逻辑是正确的。从矩形的左下角到右上角,对于每个点,我都在检查它是否位于圆内。 如果我将增量​​步长增加到超过“ 1”的任何值,我会发现代码对于矩形和圆形只是彼此“接触”的测试用例失败。但是在某些情况下,以这种方式进行操作会导致超过时间限制。如何为此逻辑优化代码?

谢谢。

1 个答案:

答案 0 :(得分:1)

此问题可以简化。我找到了时间复杂度O(1)和内存复杂度O(1)的解决方案。不必检查矩形中的每个像素,您甚至可以只考虑边界本身。

我认为有3种情况:

  1. 圆形完全在矩形内部。
  2. 矩形完全在圆内
  3. 圆形和矩形轮廓在至少一个点处相交。这是更艰难的。

我将圆心称为x0和y0。

  1. 您可以简单地选中圆的边界框,例如,它是圆的最北点(x0,y0-radius),它是圆的最南点(x0, y0 + radius),最东端(x0-radius,y0)和最西端(x0 + radius,y0)。如果它们都落在矩形内,那么问题就解决了。

  2. 如果矩形完全在圆内,则绝对意味着其角到圆心的距离小于半径。只需检查每个角的距离即可。

现在困难的部分了。

  1. 因此,正如您所知道的,处于圆形(或相交)是指某个点到中心的距离必须小于或等于半径。 但是,我们也可以对矩形检查部分进行优化。与矩形的相交可能意味着与构成矩形轮廓的线段中的至少一个相交。因此,在矩形和圆形相交的情况下,您需要检查是否有任何段距圆心的距离小于或等于半径。

编辑:同样,您的代码在几乎接触不到的测试中失败的原因可能是浮点错误。 not 不要使用==(或者在这种情况下为<=,这是相似的)来检查两个浮点(甚至是浮点和整数)值是否相同。 Java中的Math.pow()返回double。只需使用普通乘法进行平方即可。 实际上,您可能想尽可能地远离浮点,除非您不知道如何摆脱它们,并且问题说“ 0.001错误是可以接受的”或类似的说法。它们既缓慢又容易出错。

编辑2:另外,我已经编写了代码以帮助您帮助理解这一解释。我已经在站点上对其进行了测试,它适用于运行时间为1ms,内存使用率为37.7Mb的每个测试。

class Solution {

    public boolean checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) {
        //case 1: circle is fully inside rectangle
        //check the bounding box of the circle against the rectangle
        if(x_center-radius>=x1&&y_center-radius>=y1
         &&x_center+radius<=x2&&y_center+radius<=y2
          )
            return true;
        //case 2: checking closest corner against circle bounds
        int minX=(Math.abs(x_center-x1)>Math.abs(x_center-x2))?(x_center-x2):(x_center-x1);
        int minY=(Math.abs(y_center-y1)>Math.abs(y_center-y2))?(y_center-y2):(y_center-y1);
        if(minX*minX+minY*minY<=radius*radius)
            return true;
        //case 3: checking distances to segments against circle bounds
        //Checking distance from a segment to a point is alike checking
        //the distance from the line the segment is part of to a point,
        //except you have to check if the closest point from the segment
        //is actually on the segment. If it isn't, the distance from a
        //segment to a point is the minimum distance from one of its
        //corners to the point.
        if(x1<=x_center&&x_center<=x2)
            if(minY*minY<=radius*radius)
                return true;
        if(y1<=y_center&&y_center<=y2)
            if(minX*minX<=radius*radius)
                return true;
        return false;
    }
}

此代码可能会缩短。但是,从时间复杂度的角度来看,它不会比O(1)更好。