Skip to content

closest pair of points algo #943

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions divide_and_conquer/closest_pair_of_points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
The algorithm finds distance btw closest pair of points in the given n points.
Approach used -> Divide and conquer
The points are sorted based on Xco-ords
& by applying divide and conquer approach,
minimum distance is obtained recursively.

>> closest points lie on different sides of partition
This case handled by forming a strip of points
whose Xco-ords distance is less than closest_pair_dis
from mid-point's Xco-ords.
Closest pair distance is found in the strip of points. (closest_in_strip)

min(closest_pair_dis, closest_in_strip) would be the final answer.

Time complexity: O(n * (logn)^2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want you can put a reference to it. Are there any references in CLRS book?

"""


import math


def euclidean_distance_sqr(point1, point2):
return pow(point1[0] - point2[0], 2) + pow(point1[1] - point2[1], 2)


def column_based_sort(array, column = 0):
return sorted(array, key = lambda x: x[column])


def dis_between_closest_pair(points, points_counts, min_dis = float("inf")):
""" brute force approach to find distance between closest pair points

Parameters :
points, points_count, min_dis (list(tuple(int, int)), int, int)

Returns :
min_dis (float): distance between closest pair of points

"""

for i in range(points_counts - 1):
for j in range(i+1, points_counts):
current_dis = euclidean_distance_sqr(points[i], points[j])
if current_dis < min_dis:
min_dis = current_dis
return min_dis


def dis_between_closest_in_strip(points, points_counts, min_dis = float("inf")):
""" closest pair of points in strip

Parameters :
points, points_count, min_dis (list(tuple(int, int)), int, int)

Returns :
min_dis (float): distance btw closest pair of points in the strip (< min_dis)

"""

for i in range(min(6, points_counts - 1), points_counts):
for j in range(max(0, i-6), i):
current_dis = euclidean_distance_sqr(points[i], points[j])
if current_dis < min_dis:
min_dis = current_dis
return min_dis


def closest_pair_of_points_sqr(points, points_counts):
""" divide and conquer approach

Parameters :
points, points_count (list(tuple(int, int)), int)

Returns :
(float): distance btw closest pair of points

"""

# base case
if points_counts <= 3:
return dis_between_closest_pair(points, points_counts)

# recursion
mid = points_counts//2
closest_in_left = closest_pair_of_points(points[:mid], mid)
closest_in_right = closest_pair_of_points(points[mid:], points_counts - mid)
closest_pair_dis = min(closest_in_left, closest_in_right)

""" cross_strip contains the points, whose Xcoords are at a
distance(< closest_pair_dis) from mid's Xcoord
"""

cross_strip = []
for point in points:
if abs(point[0] - points[mid][0]) < closest_pair_dis:
cross_strip.append(point)

cross_strip = column_based_sort(cross_strip, 1)
closest_in_strip = dis_between_closest_in_strip(cross_strip,
len(cross_strip), closest_pair_dis)
return min(closest_pair_dis, closest_in_strip)


def closest_pair_of_points(points, points_counts):
return math.sqrt(closest_pair_of_points_sqr(points, points_counts))


points = [(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (0, 2), (5, 6), (1, 2)]
points = column_based_sort(points)
print("Distance:", closest_pair_of_points(points, len(points)))


75 changes: 75 additions & 0 deletions divide_and_conquer/max_subarray_sum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""
Given a array of length n, max_subarray_sum() finds
the maximum of sum of contiguous sub-array using divide and conquer method.

Time complexity : O(n log n)

Ref : INTRODUCTION TO ALGORITHMS THIRD EDITION
(section : 4, sub-section : 4.1, page : 70)

"""


def max_sum_from_start(array):
""" This function finds the maximum contiguous sum of array from 0 index

Parameters :
array (list[int]) : given array

Returns :
max_sum (int) : maximum contiguous sum of array from 0 index

"""
array_sum = 0
max_sum = float("-inf")
for num in array:
array_sum += num
if array_sum > max_sum:
max_sum = array_sum
return max_sum


def max_cross_array_sum(array, left, mid, right):
""" This function finds the maximum contiguous sum of left and right arrays

Parameters :
array, left, mid, right (list[int], int, int, int)

Returns :
(int) : maximum of sum of contiguous sum of left and right arrays

"""

max_sum_of_left = max_sum_from_start(array[left:mid+1][::-1])
max_sum_of_right = max_sum_from_start(array[mid+1: right+1])
return max_sum_of_left + max_sum_of_right


def max_subarray_sum(array, left, right):
""" Maximum contiguous sub-array sum, using divide and conquer method

Parameters :
array, left, right (list[int], int, int) :
given array, current left index and current right index

Returns :
int : maximum of sum of contiguous sub-array

"""

# base case: array has only one element
if left == right:
return array[right]

# Recursion
mid = (left + right) // 2
left_half_sum = max_subarray_sum(array, left, mid)
right_half_sum = max_subarray_sum(array, mid + 1, right)
cross_sum = max_cross_array_sum(array, left, mid, right)
return max(left_half_sum, right_half_sum, cross_sum)


array = [-2, -5, 6, -2, -3, 1, 5, -6]
array_length = len(array)
print("Maximum sum of contiguous subarray:", max_subarray_sum(array, 0, array_length - 1))