mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-07-05 09:21:13 +08:00
Consolidate duplicate implementations of max subarray (#8849)
* Remove max subarray sum duplicate implementations * updating DIRECTORY.md * Rename max_sum_contiguous_subsequence.py * Fix typo in dynamic_programming/max_subarray_sum.py * Remove duplicate divide and conquer max subarray * updating DIRECTORY.md --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
This commit is contained in:
112
divide_and_conquer/max_subarray.py
Normal file
112
divide_and_conquer/max_subarray.py
Normal file
@ -0,0 +1,112 @@
|
||||
"""
|
||||
The maximum subarray problem is the task of finding the continuous subarray that has the
|
||||
maximum sum within a given array of numbers. For example, given the array
|
||||
[-2, 1, -3, 4, -1, 2, 1, -5, 4], the contiguous subarray with the maximum sum is
|
||||
[4, -1, 2, 1], which has a sum of 6.
|
||||
|
||||
This divide-and-conquer algorithm finds the maximum subarray in O(n log n) time.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from collections.abc import Sequence
|
||||
from random import randint
|
||||
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
|
||||
def max_subarray(
|
||||
arr: Sequence[float], low: int, high: int
|
||||
) -> tuple[int | None, int | None, float]:
|
||||
"""
|
||||
Solves the maximum subarray problem using divide and conquer.
|
||||
:param arr: the given array of numbers
|
||||
:param low: the start index
|
||||
:param high: the end index
|
||||
:return: the start index of the maximum subarray, the end index of the
|
||||
maximum subarray, and the maximum subarray sum
|
||||
|
||||
>>> nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
|
||||
>>> max_subarray(nums, 0, len(nums) - 1)
|
||||
(3, 6, 6)
|
||||
>>> nums = [2, 8, 9]
|
||||
>>> max_subarray(nums, 0, len(nums) - 1)
|
||||
(0, 2, 19)
|
||||
>>> nums = [0, 0]
|
||||
>>> max_subarray(nums, 0, len(nums) - 1)
|
||||
(0, 0, 0)
|
||||
>>> nums = [-1.0, 0.0, 1.0]
|
||||
>>> max_subarray(nums, 0, len(nums) - 1)
|
||||
(2, 2, 1.0)
|
||||
>>> nums = [-2, -3, -1, -4, -6]
|
||||
>>> max_subarray(nums, 0, len(nums) - 1)
|
||||
(2, 2, -1)
|
||||
>>> max_subarray([], 0, 0)
|
||||
(None, None, 0)
|
||||
"""
|
||||
if not arr:
|
||||
return None, None, 0
|
||||
if low == high:
|
||||
return low, high, arr[low]
|
||||
|
||||
mid = (low + high) // 2
|
||||
left_low, left_high, left_sum = max_subarray(arr, low, mid)
|
||||
right_low, right_high, right_sum = max_subarray(arr, mid + 1, high)
|
||||
cross_left, cross_right, cross_sum = max_cross_sum(arr, low, mid, high)
|
||||
if left_sum >= right_sum and left_sum >= cross_sum:
|
||||
return left_low, left_high, left_sum
|
||||
elif right_sum >= left_sum and right_sum >= cross_sum:
|
||||
return right_low, right_high, right_sum
|
||||
return cross_left, cross_right, cross_sum
|
||||
|
||||
|
||||
def max_cross_sum(
|
||||
arr: Sequence[float], low: int, mid: int, high: int
|
||||
) -> tuple[int, int, float]:
|
||||
left_sum, max_left = float("-inf"), -1
|
||||
right_sum, max_right = float("-inf"), -1
|
||||
|
||||
summ: int | float = 0
|
||||
for i in range(mid, low - 1, -1):
|
||||
summ += arr[i]
|
||||
if summ > left_sum:
|
||||
left_sum = summ
|
||||
max_left = i
|
||||
|
||||
summ = 0
|
||||
for i in range(mid + 1, high + 1):
|
||||
summ += arr[i]
|
||||
if summ > right_sum:
|
||||
right_sum = summ
|
||||
max_right = i
|
||||
|
||||
return max_left, max_right, (left_sum + right_sum)
|
||||
|
||||
|
||||
def time_max_subarray(input_size: int) -> float:
|
||||
arr = [randint(1, input_size) for _ in range(input_size)]
|
||||
start = time.time()
|
||||
max_subarray(arr, 0, input_size - 1)
|
||||
end = time.time()
|
||||
return end - start
|
||||
|
||||
|
||||
def plot_runtimes() -> None:
|
||||
input_sizes = [10, 100, 1000, 10000, 50000, 100000, 200000, 300000, 400000, 500000]
|
||||
runtimes = [time_max_subarray(input_size) for input_size in input_sizes]
|
||||
print("No of Inputs\t\tTime Taken")
|
||||
for input_size, runtime in zip(input_sizes, runtimes):
|
||||
print(input_size, "\t\t", runtime)
|
||||
plt.plot(input_sizes, runtimes)
|
||||
plt.xlabel("Number of Inputs")
|
||||
plt.ylabel("Time taken in seconds")
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
A random simulation of this algorithm.
|
||||
"""
|
||||
from doctest import testmod
|
||||
|
||||
testmod()
|
@ -1,78 +0,0 @@
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
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),
|
||||
)
|
Reference in New Issue
Block a user