Skip to content

Commit df417c2

Browse files
committed
feat(algorithms, binary-search): split array largest sum
1 parent 8c55e90 commit df417c2

27 files changed

+1232
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Split Array Largest Sum
2+
3+
Given an integer list nums and an integer k, split nums into k non-empty subarrays such that the largest sum among these
4+
subarrays is minimized. The task is to find the minimized largest sum by choosing the split such that the largest sum of
5+
every split of subarrays is the minimum among the sum of other splits.
6+
7+
## Constraints
8+
9+
- 1 <= nums.length <= 1000
10+
- 0 <= nums[i] <= 10^4
11+
- 1 <= k <= nums.length
12+
13+
## Examples
14+
15+
![Example 1](images/examples/split_array_largest_sum_example_1.png)
16+
![Example 2](images/examples/split_array_largest_sum_example_2.png)
17+
![Example 3](images/examples/split_array_largest_sum_example_3.png)
18+
![Example 4](images/examples/split_array_largest_sum_example_4.png)
19+
20+
## Topics
21+
22+
- Array
23+
- Binary Search
24+
- Dynamic Programming
25+
- Greedy
26+
- Prefix Sum
27+
28+
## Solution
29+
30+
In a brute force method, you would try all possible ways to split the array into k subarrays, calculate the largest sum
31+
for each split, and then find the smallest among those largest sums. This approach is extremely inefficient because the
32+
number of ways to split the array grows exponentially as the size increases.
33+
34+
We reverse the process by guessing a value for the minimum largest sum and checking if it’s feasible:
35+
36+
- Instead of iterating through all splits, we only focus on testing whether a specific value allows us to split the
37+
array into k subarrays.
38+
39+
- But wait—just because one value works doesn’t mean it’s the smallest feasible value. We keep exploring smaller values
40+
to achieve the most optimized result.
41+
42+
The solution uses the binary search approach to find the optimal largest subarray sum without testing all possible splits.
43+
The binary search finds the smallest possible value of the largest subarray sum and applies searching over the range of
44+
possible values for this largest sum. But how do we guess this value? We guess the value using a certain range.
45+
Here’s how:
46+
47+
- **Left boundary**: The maximum element in the array is the minimum possible value for the largest subarray sum. This
48+
is because any valid subarray must have a sum at least as large as the largest element.
49+
50+
- **Right boundary**: The maximum possible value for the largest subarray sum is the sum of all elements in the array.
51+
You would get this sum if the entire array were one single subarray.
52+
53+
The binary search iteratively tests midpoints in the above ranges. It determines whether dividing the array results in
54+
at most k subarrays will result in the smallest largest sum. If it does, the search shifts to lower values to minimize
55+
the largest sum. Otherwise, it shifts to higher values. Still, there might be subarrays whose sum could be smaller, so
56+
the search keeps going until the search range crosses each other, i.e., **left boundary** > **right boundary**.
57+
58+
Here’s the step-by-step implementation of the solution:
59+
60+
- Start by initializing the ranges for search. The left will be the largest number in the array, and the right will be
61+
the sum of all numbers.
62+
- Use a guessing approach. Start by considering a mid value between the left and right as a test value.
63+
- Check if it is possible to divide the array into k subarrays so that the sum of no subarray is greater than mid.
64+
- Start with an empty sum and add numbers from the array. If adding the next number exceeds mid:
65+
- Start a new subarray with that number and increment the count of the subarrays.
66+
- Return FALSE if the count exceeds k. Otherwise, return TRUE.
67+
- Adjust the guessing range by checking if the number of subarrays needed is within the k and reduce the mid to see if
68+
a smaller largest sum is possible.
69+
- Otherwise, if the count of subarrays is more than k:
70+
- Increase the mid to make larger groups possible.
71+
- Continue adjusting the mid until left < right. Return left as it contains the minimized largest possible sum.
72+
73+
- Let’s look at the following illustrations to get a better understanding of the solution:
74+
75+
![Solution 1](images/solutions/split_array_largest_sum_solution_1.png)
76+
![Solution 2](images/solutions/split_array_largest_sum_solution_2.png)
77+
![Solution 3](images/solutions/split_array_largest_sum_solution_3.png)
78+
![Solution 4](images/solutions/split_array_largest_sum_solution_4.png)
79+
![Solution 5](images/solutions/split_array_largest_sum_solution_5.png)
80+
![Solution 6](images/solutions/split_array_largest_sum_solution_6.png)
81+
![Solution 7](images/solutions/split_array_largest_sum_solution_7.png)
82+
![Solution 8](images/solutions/split_array_largest_sum_solution_8.png)
83+
![Solution 9](images/solutions/split_array_largest_sum_solution_9.png)
84+
![Solution 10](images/solutions/split_array_largest_sum_solution_10.png)
85+
![Solution 11](images/solutions/split_array_largest_sum_solution_11.png)
86+
![Solution 12](images/solutions/split_array_largest_sum_solution_12.png)
87+
![Solution 13](images/solutions/split_array_largest_sum_solution_13.png)
88+
![Solution 14](images/solutions/split_array_largest_sum_solution_14.png)
89+
![Solution 15](images/solutions/split_array_largest_sum_solution_15.png)
90+
![Solution 16](images/solutions/split_array_largest_sum_solution_16.png)
91+
![Solution 17](images/solutions/split_array_largest_sum_solution_17.png)
92+
![Solution 18](images/solutions/split_array_largest_sum_solution_18.png)
93+
![Solution 19](images/solutions/split_array_largest_sum_solution_19.png)
94+
![Solution 20](images/solutions/split_array_largest_sum_solution_20.png)
95+
96+
### Time Complexity
97+
98+
The time complexity of this solution is O(n log(m)), where n is the length of the input array, and m is the difference
99+
between `max(nums)` and `sum(nums)` because the range of possible sums considered during the binary search is from
100+
`max(nums)`to `sum(nums)`. This range size determines the number of iterations in the binary search. The tighter this
101+
range, the fewer iterations are needed. However, in the worst case, it spans the full difference: `sum(nums) - max(nums)`.
102+
The time complexity becomes `n log(m)` because the `can_split` function is called `n` times for each iteration.
103+
104+
### Space Complexity
105+
106+
The time complexity of this solution is O(1) because only constant space is used.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from typing import List
2+
3+
4+
def split_array(nums: List[int], k: int) -> int:
5+
if not nums:
6+
return -1
7+
8+
left = max(nums)
9+
right = sum(nums)
10+
first_true_index = -1
11+
12+
def feasible(max_sum: int) -> bool:
13+
"""
14+
Check if we can split the array into at most k sub arrays with each sub array sum less than or equal to max_sum
15+
"""
16+
current_sum = 0
17+
# Start with one
18+
sub_array_count = 1
19+
20+
for num in nums:
21+
if current_sum + num > max_sum:
22+
current_sum = num
23+
sub_array_count += 1
24+
else:
25+
current_sum += num
26+
27+
return sub_array_count <= k
28+
29+
while left <= right:
30+
mid = (right + left) // 2
31+
if feasible(mid):
32+
first_true_index = mid
33+
# Find a smaller valid value
34+
right = mid - 1
35+
else:
36+
# Find a larger valid value
37+
left = mid + 1
38+
39+
return first_true_index
40+
41+
42+
def split_array_2(nums, k):
43+
# Set the initial search range for the largest sum:
44+
# Minimum is the largest number in the array, and maximum is the sum of all numbers
45+
left, right = max(nums), sum(nums)
46+
47+
def can_split(mid):
48+
# Initialize the count of subarrays and the current sum of the current subarray
49+
subarrays = 1
50+
current_sum = 0
51+
52+
for num in nums:
53+
# Check if adding the current number exceeds the allowed sum (mid)
54+
if current_sum + num > mid:
55+
# Increment the count of subarrays
56+
subarrays += 1
57+
# Start a new subarray with the current number
58+
current_sum = num
59+
60+
# If the number of subarrays exceeds the allowed k, return False
61+
if subarrays > k:
62+
return False
63+
else:
64+
# Otherwise, add the number to the current subarray
65+
current_sum += num
66+
67+
# Return True if the array can be split within the allowed subarray count
68+
return True
69+
70+
# Perform binary search to find the minimum largest sum
71+
while left < right:
72+
# Find the middle value of the current range
73+
mid = (left + right) // 2
74+
75+
# Check if the array can be split into k or fewer subarrays with this maximum sum
76+
if can_split(mid):
77+
# If possible, try a smaller maximum sum
78+
right = mid
79+
else:
80+
# Otherwise, increase the range to allow larger sums
81+
left = mid + 1
82+
83+
# Return the smallest maximum sum that satisfies the condition
84+
return left
91 KB
Loading
80.3 KB
Loading
74.1 KB
Loading
98.7 KB
Loading
55.8 KB
Loading
68.8 KB
Loading
65.2 KB
Loading
99 KB
Loading

0 commit comments

Comments
 (0)