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()
|
Reference in New Issue
Block a user