圆点-效果

时间:2019-02-22 08:29:19

标签: python performance loops math

我正在通过解决CodeWars Katas学习python。练习是:“编写一个计算圆点数的函数”。我的代码:

from math import sqrt
import time
start = time.time()

def points(n):
    count=0
    for i in range (-n,n+1):
        for j in range(-n,n+1):
          if abs(i)+abs(j)<=n:
            count=count+1
            continue
          if (sqrt(i**2+j**2))<=n:
             count=count+1
    return count

print (points(1000))
end = time.time()
print(end - start)

执行时间似乎太长(points(1000)为7秒,points(2000)为21秒)。如何提高效率(摆脱循环?)。

3 个答案:

答案 0 :(得分:0)

我忍不住试一试。因此,这是一种将圆分成中心正方形和四个相等的“盖帽”的方法:

[[0 0   0 0 0 0 1 0 0 0 0   0 0]
 [0 0   0 1 1 1 1 1 1 1 0   0 0]

 [0 0   1 1 1 1 1 1 1 1 1   0 0]
 [0 1   1 1 1 1 1 1 1 1 1   1 0]
 [0 1   1 1 1 1 1 1 1 1 1   1 0]
 [0 1   1 1 1 1 1 1 1 1 1   1 0]
 [1 1   1 1 1 1 1 1 1 1 1   1 1]
 [0 1   1 1 1 1 1 1 1 1 1   1 0]
 [0 1   1 1 1 1 1 1 1 1 1   1 0]
 [0 1   1 1 1 1 1 1 1 1 1   1 0]
 [0 0   1 1 1 1 1 1 1 1 1   0 0]

 [0 0   0 1 1 1 1 1 1 1 0   0 0]
 [0 0   0 0 0 0 1 0 0 0 0   0 0]]

根据评论中的建议,我们不检查单个点;相反,我们在顶盖的每一行中找到最外面的点。

为此,我们首先通过对奇数求和来廉价地计算0到N ^ 2之间的所有平方。

然后,我们遍历正方形0、1、4、9 ...(对应于x坐标),同时检测到所有与N ^ 2-y ^ 2交叉的点。 y ^ 2取自预先计算的正方形,从右到左,直到x和y相遇。

最后,我们将四个大写字母和中心正方形相加。

代码:

from itertools import accumulate

def pic(N):
    squares = 0, *accumulate(range(1, 2*N+1, 2))
    N2 = squares[-1]
    i, j = 0, N
    cap = 0
    while 2 * squares[j] > N2:
        max_x2 = N2 - squares[j]
        while squares[i] <= max_x2:
            i += 1
        cap += 2*i - 1
        j -= 1
    return 4*cap + (2*j+1)*(2*j+1)

基本相同算法的numpy版本:

import numpy as np

def pic_np(N):
    odd = np.arange(-1, 2*N+1, 2)
    odd[0] = 0
    squares = odd.cumsum()
    N2 = squares[-1]
    cut = squares.searchsorted((N2 + 1) // 2)
    cap = 2 * squares[:cut].searchsorted(N2 - squares[cut:], 'right').sum() - (N-cut+1)
    return 4*cap + (2*cut-1)*(2*cut-1)

还有一种蛮力比较方法:

def brute_force(N, show=True):
   sq = np.arange(-N, N+1)**2
   mask = sum(np.ix_(sq, sq)) <= N*N
   if show and (N <= 10):
       print(mask.view(np.uint8))
   return np.count_nonzero(mask)

答案 1 :(得分:0)

怎么样:

def points(n):
    return n * n * PI

还是不够“精确”。我们是否在看线内的圆点,正方形像素(以及该线到底在什么像素上?),..? (也许使用n-1吗?)。

答案 2 :(得分:0)

其自我解释

public static int pointsNumber(int radius) {
    int quater_updown = radius;
    //xxxxx
    for (int i = 1; i <= radius; i++) {
        quater_updown += sqrt(radius * radius - i * i);
    }
    //xxxx.
    //xxx..
    //xx...
    //x....
    //4 side and a center
    return 1 + (quater_updown) * 4;
}