如何用更节省时间的东西替换嵌套的for循环



我给出了一个矩形,其左下角和右上角的顶点坐标分别为(x1,y1(和(x2,y2(。一般点(x,y(在矩形外给出。并且还给出了整数值R。

现在我的目标是找到矩形上和内部的积分点总数,这些积分点与(x,y(的距离小于或等于R。

我所做的是:

n=0
for i in range(x1, x2+1, 1):
for j in range(y1, y2+1, 1):
if (i-x)**2+(j-y)**2<=R2:
n+=1
print(n)

我的代码效率很低,而且由于使用了嵌套for循环,所以它的时间复杂度很高。你能提供一种有效的方法来解决python中的相同问题吗?

示例:(x1,y1(=(0,0(和(x2,y2(=

设(x,y(=(-8.0(和R=9

则输出必须是3,因为只有(0,0(、(1,0(和(0,1(满足条件。

通过将圆的离散点作为一系列线来处理,可以大大降低复杂性。有了这些线,计算与矩形相交的点的数量可以在数学上完成,而无需嵌套循环。这将把复杂性从O(n^2(降低到O(n(。

例如:

x1,y1 = (0,0)
x2,y2 = (1,1)
x,y   = (-8,0)
R     = 9
n = 0 
for cy in range(y-R,y+R+1):           # cy: vertical coordinate of circle's lines
if cy not in range(y1,y2+1):          # no vertical intersection
continue
dx  = int((R**2-(cy-y)**2)**0.5)      # width of half circle at cy
cx1,cx2 = x-dx,x+dx                   # edges of circle at line cy
if cx2<x1 or cx1>x2: continue         # no horizontal intersection
n += min(x2,cx2)-max(x1,cx1)+1        # intersection with cy line
print(n) # 3

视觉:

# (x1,y1)          -----      y+3  ... no vertical intersection 
#     XXXXXXXXXXX---------    y+2  ... intersect line at y+2 with x1..x2
#     XXXXXXXXXX-----------   y+1  ... intersect line at y+1 with x1..x2
#     XXXXXXXXXX-----o-----   y    ... intersect line at y+0 with x1..x2
#     XXXXXXXXXX-----------   y-1  ... intersect line at y-1 with x1..x2
#     XXXXXXXXXXX---------    y-2  ... intersect line at y-2 with x1..x2
#     XXXXXXXXXXXX -----      y-3  ... no horizontal intersection
#     XXXXXXXXXXXX 
#     XXXXXXXXXXXX
#             (x2,y2)

查找圆与矩形的交点。

将相交类型分类为cap(圆线段(、类似扇形、没有扇形的线段,也许还有其他类型。

按Y坐标扫描,每个Y得到矩形和圆形内对应的最后一个X。

X - edgeX值添加到扇形交叉点的结果中。CCD_ 2可以是x1或x2,这取决于哪个边被圆截除。

对于圆帽,取两个X点并加上它们的差。

使用这种方法,复杂度相对于矩形大小是线性的,但需要付出一些努力来对交集进行分类。

您可以将numpy用于矢量化的bruteforce版本:

import numpy as np
P_x,P_y=-8,0
R=9
x_min,x_max=0,1
y_min,y_max=0,1
xx,yy=np.meshgrid(np.arange(x_min,x_max+1),np.arange(x_min,x_max+1))
distances=((xx-P_x)**2+(yy-P_y)**2)
print(distances)
print(np.sum(distances<=R**2))

然而,通过思考半分析方法,你可能会更快。由于numpy例程的执行速度较高,该公式的计算复杂度保持为具有较低前置因子的矩形面积的量级。但这个问题可以归结为只看圆的边界。并决定哪些点的子集位于边界内。

最新更新