-
Notifications
You must be signed in to change notification settings - Fork 43
/
split-array-largest-sum.py
158 lines (118 loc) · 5.82 KB
/
split-array-largest-sum.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
"""
410. Split Array Largest Sum
Hard
Given an array nums which consists of non-negative integers and an integer m, you can split the array into m non-empty continuous subarrays.
Write an algorithm to minimize the largest sum among these m subarrays.
Example 1:
Input: nums = [7,2,5,10,8], m = 2
Output: 18
Explanation:
There are four ways to split nums into two subarrays.
The best way is to split it into [7,2,5] and [10,8],
where the largest sum among the two subarrays is only 18.
Example 2:
Input: nums = [1,2,3,4,5], m = 2
Output: 9
Example 3:
Input: nums = [1,4,4], m = 3
Output: 4
Constraints:
1 <= nums.length <= 1000
0 <= nums[i] <= 106
1 <= m <= min(50, nums.length)
"""
# V0
# V1
# IDEA : BINARY SEARCH
# https://leetcode.com/problems/split-array-largest-sum/solution/
class Solution:
def splitArray(self, nums: List[int], m: int) -> int:
def min_subarrays_required(max_sum_allowed: int) -> int:
current_sum = 0
splits_required = 0
for element in nums:
# Add element only if the sum doesn't exceed max_sum_allowed
if current_sum + element <= max_sum_allowed:
current_sum += element
else:
# If the element addition makes sum more than max_sum_allowed
# Increment the splits required and reset sum
current_sum = element
splits_required += 1
# Return the number of subarrays, which is the number of splits + 1
return splits_required + 1
# Define the left and right boundary of binary search
left = max(nums)
right = sum(nums)
while left <= right:
# Find the mid value
max_sum_allowed = (left + right) // 2
# Find the minimum splits. If splits_required is less than
# or equal to m move towards left i.e., smaller values
if min_subarrays_required(max_sum_allowed) <= m:
right = max_sum_allowed - 1
minimum_largest_split_sum = max_sum_allowed
else:
# Move towards right if splits_required is more than m
left = max_sum_allowed + 1
return minimum_largest_split_sum
# V1'
# IDEA : TOP DOWN DP
# https://leetcode.com/problems/split-array-largest-sum/solution/
class Solution:
def splitArray(self, nums: List[int], m: int) -> int:
n = len(nums)
# Create a prefix sum array of nums.
prefix_sum = [0] + list(itertools.accumulate(nums))
@functools.lru_cache(None)
def get_min_largest_split_sum(curr_index: int, subarray_count: int):
# Base Case: If there is only one subarray left, then all of the remaining numbers
# must go in the current subarray. So return the sum of the remaining numbers.
if subarray_count == 1:
return prefix_sum[n] - prefix_sum[curr_index]
# Otherwise, use the recurrence relation to determine the minimum largest subarray sum
# between curr_index and the end of the array with subarray_count subarrays remaining.
minimum_largest_split_sum = prefix_sum[n]
for i in range(curr_index, n - subarray_count + 1):
# Store the sum of the first subarray.
first_split_sum = prefix_sum[i + 1] - prefix_sum[curr_index]
# Find the maximum subarray sum for the current first split.
largest_split_sum = max(first_split_sum,
get_min_largest_split_sum(i + 1, subarray_count - 1))
# Find the minimum among all possible combinations.
minimum_largest_split_sum = min(minimum_largest_split_sum, largest_split_sum)
if first_split_sum >= minimum_largest_split_sum:
break
return minimum_largest_split_sum
return get_min_largest_split_sum(0, m)
# V1''
# IDEA : BOTTOM UP DP
# https://leetcode.com/problems/split-array-largest-sum/solution/
class Solution:
def splitArray(self, nums: List[int], m: int) -> int:
n = len(nums)
memo = [[0] * (m + 1) for _ in range(n)]
# Create a prefix sum array of nums.
prefix_sum = [0] + list(itertools.accumulate(nums))
for subarray_count in range(1, m + 1):
for curr_index in range(n):
# Base Case: If there is only one subarray left, then all of the remaining numbers
# must go in the current subarray. So return the sum of the remaining numbers.
if subarray_count == 1:
memo[curr_index][subarray_count] = prefix_sum[n] - prefix_sum[curr_index]
continue
# Otherwise, use the recurrence relation to determine the minimum largest subarray sum
# between curr_index and the end of the array with subarray_count subarrays remaining.
minimum_largest_split_sum = prefix_sum[n]
for i in range(curr_index, n - subarray_count + 1):
# Store the sum of the first subarray.
first_split_sum = prefix_sum[i + 1] - prefix_sum[curr_index]
# Find the maximum subarray sum for the current first split.
largest_split_sum = max(first_split_sum, memo[i + 1][subarray_count - 1])
# Find the minimum among all possible combinations.
minimum_largest_split_sum = min(minimum_largest_split_sum, largest_split_sum)
if first_split_sum >= minimum_largest_split_sum:
break
memo[curr_index][subarray_count] = minimum_largest_split_sum
return memo[0][m]
# V2