-
Notifications
You must be signed in to change notification settings - Fork 5
/
closest_pair.py
129 lines (94 loc) · 3.66 KB
/
closest_pair.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""
The closest pair of points problem or closest pair problem is a problem of computational geometry:
given n points in metric space, find a pair of points with the smallest distance between them.
The closest pair problem for points in the Euclidean plane[1] was among the first geometric problems that
were treated at the origins of the systematic study of the computational complexity of geometric algorithms. [Wikipedia]
"""
import math
def _distance(point1, point2):
"""
Function for calculation distance between 2 points
Args:
point1: first point with coordinates as tuple (x, y)
point2: first point with coordinates as tuple (x, y)
Returns:
Distance between 2 points
"""
return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
def brute_force_distance(points):
"""
Brute force solution for closest pair problem
Complexity: O(n^2)
Args:
points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)]
Returns:
Minimum distance between points
Examples:
>>> n_log_n_squared_distance([(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)])
1.4142135623730951
"""
if len(points) == 1:
return 0
# Calculating distance between first two points
min_d = _distance(points[0], points[1])
for x1, point1 in enumerate(points):
for x2, point2 in enumerate(points):
distance = _distance(point1, point2)
if (x1 != x2) and distance < min_d:
min_d = distance
return min_d
def n_log_n_squared_distance(points):
"""
O(N (LogN)^2) solution for closest pair problem
Complexity: O(n (log n)^2)
Args:
points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)]
Returns:
Minimum distance between points
Examples:
>>> n_log_n_squared_distance([(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)])
1.4142135623730951
"""
# Points have to be sorted by x coordinate
points = sorted(points, key=lambda x: x[0])
return _n_log_n_squared_distance(points)
def _n_log_n_squared_distance(points):
"""
O(N (LogN)^2) solution for closest pair problem
Complexity: O(n (log n)^2)
Args:
points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)]
Returns:
Minimum distance between points
"""
if len(points) == 1:
return 0
if len(points) <= 3:
return brute_force_distance(points)
# splitting points to the 2 parts
mid = len(points) // 2
min_d1 = n_log_n_squared_distance(points[:mid])
min_d2 = n_log_n_squared_distance(points[mid:])
min_d = min(min_d1, min_d2)
strip = []
# Adding point to the strip array if the distance between point and the "vertical" line that we split
# is less than minimum distance that we have find.
for point in points:
x = point[0]
if abs(x - points[mid][0]) < min_d:
strip.append(point)
return min(min_d, _closest_split_pair(strip, min_d))
def _closest_split_pair(points, delta):
"""
Function for check boundaries points (points that close to the split line than minimum delta)
Args:
points: list of points in the following format [(x1, y1), (x2, y2), ... , (xn, yn)]
delta: delta (minimum distance)
Returns:
minimum distance between points
"""
for i in range(len(points)):
for j in range(i + 1, len(points)):
if (points[j][1] - points[i][1]) < delta and _distance(points[i], points[j]) < delta:
delta = _distance(points[i], points[j])
return delta