mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-27 15:01:08 +00: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:
parent
c9ee6ed188
commit
a0eec90466
|
@ -293,7 +293,7 @@
|
|||
* [Inversions](divide_and_conquer/inversions.py)
|
||||
* [Kth Order Statistic](divide_and_conquer/kth_order_statistic.py)
|
||||
* [Max Difference Pair](divide_and_conquer/max_difference_pair.py)
|
||||
* [Max Subarray Sum](divide_and_conquer/max_subarray_sum.py)
|
||||
* [Max Subarray](divide_and_conquer/max_subarray.py)
|
||||
* [Mergesort](divide_and_conquer/mergesort.py)
|
||||
* [Peak](divide_and_conquer/peak.py)
|
||||
* [Power](divide_and_conquer/power.py)
|
||||
|
@ -324,8 +324,7 @@
|
|||
* [Matrix Chain Order](dynamic_programming/matrix_chain_order.py)
|
||||
* [Max Non Adjacent Sum](dynamic_programming/max_non_adjacent_sum.py)
|
||||
* [Max Product Subarray](dynamic_programming/max_product_subarray.py)
|
||||
* [Max Sub Array](dynamic_programming/max_sub_array.py)
|
||||
* [Max Sum Contiguous Subsequence](dynamic_programming/max_sum_contiguous_subsequence.py)
|
||||
* [Max Subarray Sum](dynamic_programming/max_subarray_sum.py)
|
||||
* [Min Distance Up Bottom](dynamic_programming/min_distance_up_bottom.py)
|
||||
* [Minimum Coin Change](dynamic_programming/minimum_coin_change.py)
|
||||
* [Minimum Cost Path](dynamic_programming/minimum_cost_path.py)
|
||||
|
@ -591,12 +590,10 @@
|
|||
* [Is Square Free](maths/is_square_free.py)
|
||||
* [Jaccard Similarity](maths/jaccard_similarity.py)
|
||||
* [Juggler Sequence](maths/juggler_sequence.py)
|
||||
* [Kadanes](maths/kadanes.py)
|
||||
* [Karatsuba](maths/karatsuba.py)
|
||||
* [Krishnamurthy Number](maths/krishnamurthy_number.py)
|
||||
* [Kth Lexicographic Permutation](maths/kth_lexicographic_permutation.py)
|
||||
* [Largest Of Very Large Numbers](maths/largest_of_very_large_numbers.py)
|
||||
* [Largest Subarray Sum](maths/largest_subarray_sum.py)
|
||||
* [Least Common Multiple](maths/least_common_multiple.py)
|
||||
* [Line Length](maths/line_length.py)
|
||||
* [Liouville Lambda](maths/liouville_lambda.py)
|
||||
|
@ -733,7 +730,6 @@
|
|||
* [Linear Congruential Generator](other/linear_congruential_generator.py)
|
||||
* [Lru Cache](other/lru_cache.py)
|
||||
* [Magicdiamondpattern](other/magicdiamondpattern.py)
|
||||
* [Maximum Subarray](other/maximum_subarray.py)
|
||||
* [Maximum Subsequence](other/maximum_subsequence.py)
|
||||
* [Nested Brackets](other/nested_brackets.py)
|
||||
* [Number Container System](other/number_container_system.py)
|
||||
|
|
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),
|
||||
)
|
|
@ -1,93 +0,0 @@
|
|||
"""
|
||||
author : Mayank Kumar Jha (mk9440)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def find_max_sub_array(a, low, high):
|
||||
if low == high:
|
||||
return low, high, a[low]
|
||||
else:
|
||||
mid = (low + high) // 2
|
||||
left_low, left_high, left_sum = find_max_sub_array(a, low, mid)
|
||||
right_low, right_high, right_sum = find_max_sub_array(a, mid + 1, high)
|
||||
cross_left, cross_right, cross_sum = find_max_cross_sum(a, 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
|
||||
else:
|
||||
return cross_left, cross_right, cross_sum
|
||||
|
||||
|
||||
def find_max_cross_sum(a, low, mid, high):
|
||||
left_sum, max_left = -999999999, -1
|
||||
right_sum, max_right = -999999999, -1
|
||||
summ = 0
|
||||
for i in range(mid, low - 1, -1):
|
||||
summ += a[i]
|
||||
if summ > left_sum:
|
||||
left_sum = summ
|
||||
max_left = i
|
||||
summ = 0
|
||||
for i in range(mid + 1, high + 1):
|
||||
summ += a[i]
|
||||
if summ > right_sum:
|
||||
right_sum = summ
|
||||
max_right = i
|
||||
return max_left, max_right, (left_sum + right_sum)
|
||||
|
||||
|
||||
def max_sub_array(nums: list[int]) -> int:
|
||||
"""
|
||||
Finds the contiguous subarray which has the largest sum and return its sum.
|
||||
|
||||
>>> max_sub_array([-2, 1, -3, 4, -1, 2, 1, -5, 4])
|
||||
6
|
||||
|
||||
An empty (sub)array has sum 0.
|
||||
>>> max_sub_array([])
|
||||
0
|
||||
|
||||
If all elements are negative, the largest subarray would be the empty array,
|
||||
having the sum 0.
|
||||
>>> max_sub_array([-1, -2, -3])
|
||||
0
|
||||
>>> max_sub_array([5, -2, -3])
|
||||
5
|
||||
>>> max_sub_array([31, -41, 59, 26, -53, 58, 97, -93, -23, 84])
|
||||
187
|
||||
"""
|
||||
best = 0
|
||||
current = 0
|
||||
for i in nums:
|
||||
current += i
|
||||
current = max(current, 0)
|
||||
best = max(best, current)
|
||||
return best
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
A random simulation of this algorithm.
|
||||
"""
|
||||
import time
|
||||
from random import randint
|
||||
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
inputs = [10, 100, 1000, 10000, 50000, 100000, 200000, 300000, 400000, 500000]
|
||||
tim = []
|
||||
for i in inputs:
|
||||
li = [randint(1, i) for j in range(i)]
|
||||
strt = time.time()
|
||||
(find_max_sub_array(li, 0, len(li) - 1))
|
||||
end = time.time()
|
||||
tim.append(end - strt)
|
||||
print("No of Inputs Time Taken")
|
||||
for i in range(len(inputs)):
|
||||
print(inputs[i], "\t\t", tim[i])
|
||||
plt.plot(inputs, tim)
|
||||
plt.xlabel("Number of Inputs")
|
||||
plt.ylabel("Time taken in seconds ")
|
||||
plt.show()
|
60
dynamic_programming/max_subarray_sum.py
Normal file
60
dynamic_programming/max_subarray_sum.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
"""
|
||||
The maximum subarray sum problem is the task of finding the maximum sum that can be
|
||||
obtained from a contiguous subarray 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], so the maximum subarray sum is 6.
|
||||
|
||||
Kadane's algorithm is a simple dynamic programming algorithm that solves the maximum
|
||||
subarray sum problem in O(n) time and O(1) space.
|
||||
|
||||
Reference: https://en.wikipedia.org/wiki/Maximum_subarray_problem
|
||||
"""
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
def max_subarray_sum(
|
||||
arr: Sequence[float], allow_empty_subarrays: bool = False
|
||||
) -> float:
|
||||
"""
|
||||
Solves the maximum subarray sum problem using Kadane's algorithm.
|
||||
:param arr: the given array of numbers
|
||||
:param allow_empty_subarrays: if True, then the algorithm considers empty subarrays
|
||||
|
||||
>>> max_subarray_sum([2, 8, 9])
|
||||
19
|
||||
>>> max_subarray_sum([0, 0])
|
||||
0
|
||||
>>> max_subarray_sum([-1.0, 0.0, 1.0])
|
||||
1.0
|
||||
>>> max_subarray_sum([1, 2, 3, 4, -2])
|
||||
10
|
||||
>>> max_subarray_sum([-2, 1, -3, 4, -1, 2, 1, -5, 4])
|
||||
6
|
||||
>>> max_subarray_sum([2, 3, -9, 8, -2])
|
||||
8
|
||||
>>> max_subarray_sum([-2, -3, -1, -4, -6])
|
||||
-1
|
||||
>>> max_subarray_sum([-2, -3, -1, -4, -6], allow_empty_subarrays=True)
|
||||
0
|
||||
>>> max_subarray_sum([])
|
||||
0
|
||||
"""
|
||||
if not arr:
|
||||
return 0
|
||||
|
||||
max_sum = 0 if allow_empty_subarrays else float("-inf")
|
||||
curr_sum = 0.0
|
||||
for num in arr:
|
||||
curr_sum = max(0 if allow_empty_subarrays else num, curr_sum + num)
|
||||
max_sum = max(max_sum, curr_sum)
|
||||
|
||||
return max_sum
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from doctest import testmod
|
||||
|
||||
testmod()
|
||||
|
||||
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
|
||||
print(f"{max_subarray_sum(nums) = }")
|
|
@ -1,20 +0,0 @@
|
|||
def max_subarray_sum(nums: list) -> int:
|
||||
"""
|
||||
>>> max_subarray_sum([6 , 9, -1, 3, -7, -5, 10])
|
||||
17
|
||||
"""
|
||||
if not nums:
|
||||
return 0
|
||||
n = len(nums)
|
||||
|
||||
res, s, s_pre = nums[0], nums[0], nums[0]
|
||||
for i in range(1, n):
|
||||
s = max(nums[i], s_pre + nums[i])
|
||||
s_pre = s
|
||||
res = max(res, s)
|
||||
return res
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
nums = [6, 9, -1, 3, -7, -5, 10]
|
||||
print(max_subarray_sum(nums))
|
|
@ -1,63 +0,0 @@
|
|||
"""
|
||||
Kadane's algorithm to get maximum subarray sum
|
||||
https://medium.com/@rsinghal757/kadanes-algorithm-dynamic-programming-how-and-why-does-it-work-3fd8849ed73d
|
||||
https://en.wikipedia.org/wiki/Maximum_subarray_problem
|
||||
"""
|
||||
test_data: tuple = ([-2, -8, -9], [2, 8, 9], [-1, 0, 1], [0, 0], [])
|
||||
|
||||
|
||||
def negative_exist(arr: list) -> int:
|
||||
"""
|
||||
>>> negative_exist([-2,-8,-9])
|
||||
-2
|
||||
>>> [negative_exist(arr) for arr in test_data]
|
||||
[-2, 0, 0, 0, 0]
|
||||
"""
|
||||
arr = arr or [0]
|
||||
max_number = arr[0]
|
||||
for i in arr:
|
||||
if i >= 0:
|
||||
return 0
|
||||
elif max_number <= i:
|
||||
max_number = i
|
||||
return max_number
|
||||
|
||||
|
||||
def kadanes(arr: list) -> int:
|
||||
"""
|
||||
If negative_exist() returns 0 than this function will execute
|
||||
else it will return the value return by negative_exist function
|
||||
|
||||
For example: arr = [2, 3, -9, 8, -2]
|
||||
Initially we set value of max_sum to 0 and max_till_element to 0 than when
|
||||
max_sum is less than max_till particular element it will assign that value to
|
||||
max_sum and when value of max_till_sum is less than 0 it will assign 0 to i
|
||||
and after that whole process, return the max_sum
|
||||
So the output for above arr is 8
|
||||
|
||||
>>> kadanes([2, 3, -9, 8, -2])
|
||||
8
|
||||
>>> [kadanes(arr) for arr in test_data]
|
||||
[-2, 19, 1, 0, 0]
|
||||
"""
|
||||
max_sum = negative_exist(arr)
|
||||
if max_sum < 0:
|
||||
return max_sum
|
||||
|
||||
max_sum = 0
|
||||
max_till_element = 0
|
||||
|
||||
for i in arr:
|
||||
max_till_element += i
|
||||
max_sum = max(max_sum, max_till_element)
|
||||
max_till_element = max(max_till_element, 0)
|
||||
return max_sum
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
print("Enter integer values sepatated by spaces")
|
||||
arr = [int(x) for x in input().split()]
|
||||
print(f"Maximum subarray sum of {arr} is {kadanes(arr)}")
|
||||
except ValueError:
|
||||
print("Please enter integer values.")
|
|
@ -1,21 +0,0 @@
|
|||
from sys import maxsize
|
||||
|
||||
|
||||
def max_sub_array_sum(a: list, size: int = 0):
|
||||
"""
|
||||
>>> max_sub_array_sum([-13, -3, -25, -20, -3, -16, -23, -12, -5, -22, -15, -4, -7])
|
||||
-3
|
||||
"""
|
||||
size = size or len(a)
|
||||
max_so_far = -maxsize - 1
|
||||
max_ending_here = 0
|
||||
for i in range(0, size):
|
||||
max_ending_here = max_ending_here + a[i]
|
||||
max_so_far = max(max_so_far, max_ending_here)
|
||||
max_ending_here = max(max_ending_here, 0)
|
||||
return max_so_far
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
a = [-13, -3, -25, -20, 1, -16, -23, -12, -5, -22, -15, -4, -7]
|
||||
print(("Maximum contiguous sum is", max_sub_array_sum(a, len(a))))
|
|
@ -1,32 +0,0 @@
|
|||
from collections.abc import Sequence
|
||||
|
||||
|
||||
def max_subarray_sum(nums: Sequence[int]) -> int:
|
||||
"""Return the maximum possible sum amongst all non - empty subarrays.
|
||||
|
||||
Raises:
|
||||
ValueError: when nums is empty.
|
||||
|
||||
>>> max_subarray_sum([1,2,3,4,-2])
|
||||
10
|
||||
>>> max_subarray_sum([-2,1,-3,4,-1,2,1,-5,4])
|
||||
6
|
||||
"""
|
||||
if not nums:
|
||||
raise ValueError("Input sequence should not be empty")
|
||||
|
||||
curr_max = ans = nums[0]
|
||||
nums_len = len(nums)
|
||||
|
||||
for i in range(1, nums_len):
|
||||
num = nums[i]
|
||||
curr_max = max(curr_max + num, num)
|
||||
ans = max(curr_max, ans)
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
n = int(input("Enter number of elements : ").strip())
|
||||
array = list(map(int, input("\nEnter the numbers : ").strip().split()))[:n]
|
||||
print(max_subarray_sum(array))
|
Loading…
Reference in New Issue
Block a user