Skip to content

Commit 9ff06d4

Browse files
committed
410 Split Array Largest Sum
1 parent 536614e commit 9ff06d4

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

410 Split Array Largest Sum.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/python3
2+
"""
3+
Given an array which consists of non-negative integers and an integer m, you can
4+
split the array into m non-empty continuous subarrays. Write an algorithm to
5+
minimize the largest sum among these m subarrays.
6+
7+
Note:
8+
If n is the length of array, assume the following constraints are satisfied:
9+
10+
1 ≤ n ≤ 1000
11+
1 ≤ m ≤ min(50, n)
12+
Examples:
13+
14+
Input:
15+
nums = [7,2,5,10,8]
16+
m = 2
17+
18+
Output:
19+
18
20+
21+
Explanation:
22+
There are four ways to split nums into two subarrays.
23+
The best way is to split it into [7,2,5] and [10,8],
24+
where the largest sum among the two subarrays is only 18.
25+
"""
26+
from typing import List
27+
from functools import lru_cache
28+
29+
30+
class SolutionDP:
31+
def splitArray(self, nums: List[int], m: int) -> int:
32+
"""
33+
non-aftereffect, dp
34+
Let F[l][k] be the minimized max sum in nums[:l] with k parts
35+
F[l][k] = max(F[j][k-1], sum(nums[j:l])), minimize over j
36+
"""
37+
n = len(nums)
38+
sums = [0]
39+
for e in nums:
40+
sums.append(sums[-1] + e)
41+
42+
F = [[float("inf") for _ in range(m + 1)] for _ in range(n + 1)]
43+
for l in range(1, n + 1):
44+
F[l][1] = sums[l] - sums[0]
45+
# or F[0][0] = 0
46+
47+
for l in range(1, n + 1):
48+
for k in range(1, m + 1):
49+
for j in range(l):
50+
F[l][k] = min(
51+
F[l][k], max(F[j][k-1], sums[l] - sums[j])
52+
)
53+
54+
return F[n][m]
55+
56+
57+
class Solution:
58+
def splitArray(self, nums: List[int], m: int) -> int:
59+
"""
60+
Binary search over the subarray sum values
61+
"""
62+
lo = max(nums)
63+
hi = sum(nums) + 1
64+
ret = hi
65+
while lo < hi:
66+
mid = (lo + hi) // 2
67+
cnt = 1 # pitfall, initial is 1 (the 1st running sum)
68+
cur_sum = 0
69+
for e in nums:
70+
if cur_sum + e > mid:
71+
cnt += 1
72+
cur_sum = e
73+
else:
74+
cur_sum += e
75+
76+
if cnt <= m:
77+
ret = min(ret, mid) # pitfall. Condition satisfied
78+
hi = mid
79+
else:
80+
lo = mid + 1
81+
82+
return ret
83+
84+
85+
class SolutionTLE2:
86+
def __init__(self):
87+
self.sums = [0]
88+
89+
def splitArray(self, nums: List[int], m: int) -> int:
90+
"""
91+
memoization with 1 less param
92+
"""
93+
for n in nums:
94+
self.sums.append(self.sums[-1] + n)
95+
96+
ret = self.dfs(len(nums), m)
97+
return ret
98+
99+
@lru_cache(maxsize=None)
100+
def dfs(self, hi, m):
101+
"""
102+
j break the nums[:hi] into left and right part
103+
"""
104+
if m == 1:
105+
return self.sums[hi] - self.sums[0]
106+
107+
mini = float("inf")
108+
for j in range(hi):
109+
right = self.sums[hi] - self.sums[j]
110+
left = self.dfs(j, m - 1)
111+
# minimize the max
112+
mini = min(mini, max(left, right))
113+
114+
return mini
115+
116+
117+
class SolutionTLE:
118+
def __init__(self):
119+
self.sums = [0]
120+
121+
def splitArray(self, nums: List[int], m: int) -> int:
122+
"""
123+
Minimize the largest subarray sum
124+
125+
backtracking + memoization
126+
"""
127+
for n in nums:
128+
self.sums.append(self.sums[-1] + n)
129+
ret = self.dfs(tuple(nums), 0, len(nums), m)
130+
return ret
131+
132+
@lru_cache(maxsize=None)
133+
def dfs(self, nums, lo, hi, m):
134+
"""
135+
j break the nums[lo:hi] into left and right part
136+
"""
137+
if m == 1:
138+
return self.sums[hi] - self.sums[lo]
139+
140+
mini = float("inf")
141+
for j in range(lo, hi):
142+
left = self.sums[j] - self.sums[lo]
143+
right = self.dfs(nums, j, hi, m - 1)
144+
# minimize the max
145+
mini = min(mini, max(left, right))
146+
147+
return mini
148+
149+
150+
if __name__ == "__main__":
151+
assert Solution().splitArray([1, 4, 4], 3) == 4
152+
assert Solution().splitArray([7,2,5,10,8], 2) == 18

0 commit comments

Comments
 (0)