Split Array Largest Sum

Hard Top 250
Associated Patterns
Interviewed At (Company Tags)
GoogleAmazonMicrosoftMeta

Problem Description

Given an integer array nums and an integer k, split nums into k non-empty contiguous subarrays such that the largest sum of any subarray is minimized.

Return the minimized largest sum of the split.

A subarray is a contiguous part of the array.


Examples

Example 1:

Input: nums = [7,2,5,10,8], k = 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], k = 2 Output: 9 Explanation: There are four ways to split nums into two subarrays. The best way is to split it into [1,2,3] and [4,5], where the largest sum among the two subarrays is only 9.


Constraints

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 10⁶
  • 1 <= k <= min(50, nums.length)

Binary Search on Sum Space

The minimized largest sum must lie in the range [max(nums), sum(nums)]. If we split the array such that no subarray exceeds sum target, we can greedy pack the elements. We run binary search on this sum range. Set left = max(nums) and right = sum(nums). At each step, calculate the midpoint sum mid. Determine if we can partition the array into at most k subarrays such that no subarray sum exceeds mid.

  • If it is possible, mid is a valid partition limit. We record it as a candidate and attempt to find a smaller sum by searching the left half: right = mid - 1.
  • If it takes too many partitions, mid is too small, so we search the right half: left = mid + 1.

Solution 1: Binary Search on Subarray Sum

Perform binary search over possible maximum subarray sums, validating partition counts.

class Solution {
    public int splitArray(int[] nums, int k) {
        int left = 0;
        int right = 0;
        for (int num : nums) {
            left = Math.max(left, num); // maximum single element sum
            right += num; // sum of all elements
        }

        int result = right;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (canSplit(nums, mid, k)) {
                result = mid; // record candidate
                right = mid - 1; // try smaller sum limits
            } else {
                left = mid + 1; // try larger sum limits
            }
        }
        return result;
    }

    private boolean canSplit(int[] nums, int maxSumLimit, int k) {
        int subarrayCount = 1;
        int currentSum = 0;

        for (int num : nums) {
            if (currentWeightPlusNumExceedsLimit(currentSum, num, maxSumLimit)) {
                subarrayCount++;
                currentSum = 0;
            }
            currentSum += num;
        }
        return subarrayCount <= k;
    }

    private boolean currentWeightPlusNumExceedsLimit(int sum, int val, int limit) {
        return sum + val > limit;
    }
}
class Solution:
    def splitArray(self, nums: list[int], k: int) -> int:
        left = max(nums)
        right = sum(nums)
        result = right
        
        def can_split(max_sum_limit: int) -> bool:
            subarray_count = 1
            current_sum = 0
            for num in nums:
                if current_sum + num > max_sum_limit:
                    subarray_count += 1
                    current_sum = 0
                current_sum += num
            return subarray_count <= k

        while left <= right:
            mid = left + (right - left) // 2
            if can_split(mid):
                result = mid  # record candidate
                right = mid - 1  # try smaller
            else:
                left = mid + 1  # try larger
                
        return result
#include <vector>
#include <numeric>
#include <algorithm>

class Solution {
private:
    bool canSplit(const std::vector<int>& nums, int maxSumLimit, int k) {
        int subarrayCount = 1;
        int currentSum = 0;
        for (int num : nums) {
            if (currentSum + num > maxSumLimit) {
                subarrayCount++;
                currentSum = 0;
            }
            currentSum += num;
        }
        return subarrayCount <= k;
    }

public:
    int splitArray(std::vector<int>& nums, int k) {
        int left = *std::max_element(nums.begin(), nums.end());
        int right = std::accumulate(nums.begin(), nums.end(), 0);
        int result = right;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (canSplit(nums, mid, k)) {
                result = mid;
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return result;
    }
};

Complexity Analysis

  • Time Complexity: O(n log m) where n is the number of elements in the array and m is the sum of all elements. The binary search runs in log m steps, and each validation pass takes O(n) time.
  • Space Complexity: O(1) auxiliary space as we track boundaries using simple variables.

Where It Breaks

This solution depends on the subarrays being contiguous. If we can group elements non-contiguously, this greedy partition check fails, and the problem becomes NP-hard.


Common Mistakes

  • Incorrect lower bound: Initializing left to 0 or 1 instead of max(nums). If the maximum sum limit is smaller than a single element, the element can never fit in any partition, violating the model boundaries.
  • Off-by-one errors on partition count: Initializing the count of subarrays to 0 instead of 1.

Frequently Asked Questions

How does this differ from the Book Allocation Problem? It is mathematically identical. Both problems ask to partition a sorted/unsorted array of values into k groups such that the maximum group sum is minimized.

What happens if k equals the array length? The binary search will converge to max(nums), since each element forms its own subarray.


← All Problems