LeetCode Solution, Hard, 410. Split Array Largest Sum

410. Split Array Largest Sum

題目敘述

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] <= 10**6
  • 1 <= m <= min(50, nums.length)

題目翻譯

今天有一個非負數的整數陣列 nums,然後一個非負數整數 m。今天需要把 nums 拆成 m 個陣列,然後試著找出在這拆解的各種組合之中,其子陣列總和是最小的。

解法解析

這題真的是難呢,但是解法卻讓這題一下變得簡單許多,是使用了 Binary Search。其概念是,我們今天不拆分 nums 而是來猜總和,這邊先定義為 X。其 X 的範圍必定是在 nums 中元素的最大值和其全部元素的總和中:nums.max() <= X <= nums.sum()。所以這題就會變得是我們在這個範圍中找出符合其條件的值,就會是 X

一下子讓題目變簡單了,真的是很優雅的解法呀

解法範例

Go

func splitArray(nums []int, m int) int {
    var minLargestSplitSum int
    var left int
    var right int

    for _, num := range nums {
        if num > left {
            left = num
        }
        right += num
    }

    for left <= right {
        maxSumAllowed := (left + right) / 2
        if minSubarraysRequired(nums, maxSumAllowed) <= m {
            right = maxSumAllowed - 1
            minLargestSplitSum = maxSumAllowed
        } else {
            left = maxSumAllowed + 1
        }
    }

    return minLargestSplitSum
}

func minSubarraysRequired(nums []int, maxSumAllowed int) int {
    currentSum := 0
    splitsRequired := 0

    for _, element := range nums {
        if currentSum+element <= maxSumAllowed {
            currentSum += element
        } else {
            currentSum = element
            splitsRequired++
        }
    }

    splitsRequired++
    return splitsRequired
}

JavaScript

/**
 * @param {number[]} nums
 * @param {number} m
 * @return {number}
 */
var splitArray = function (nums, m) {
    const minSubarraysRequired = (maxSumAllowed) => {
        let currentSum = 0,
            splitsRequired = 0;
        for (const element of nums) {
            if (currentSum + element <= maxSumAllowed) {
                currentSum += element;
            } else {
                currentSum = element;
                splitsRequired++;
            }
        }
        return splitsRequired + 1;
    };

    let minimumLargestSplitSum = 0,
        left = Math.max(...nums),
        right = nums.reduce((a, b) => a + b, 0);
    while (left <= right) {
        const maxSumAllowed = Math.floor((left + right) / 2);

        if (minSubarraysRequired(maxSumAllowed) <= m) {
            right = maxSumAllowed - 1;
            minimumLargestSplitSum = maxSumAllowed;
        } else {
            left = maxSumAllowed + 1;
        }
    }

    return minimumLargestSplitSum;
};

Kotlin

class Solution {
    fun splitArray(nums: IntArray, m: Int): Int {
        var left = 0L
        var right = 0L
        for (num in nums) {
            left = maxOf(left, num.toLong())
            right += num
        }
        var minLargeestSplitSum = 0L

        while (left <= right) {
            val maxSumAllowed = left + (right - left) / 2
            if (minSubArraysRequired(nums, maxSumAllowed) <= m) {
                right = maxSumAllowed - 1
                minLargeestSplitSum = maxSumAllowed
            } else {
                left = maxSumAllowed + 1
            }
        }

        return minLargeestSplitSum.toInt()
    }

    private fun minSubArraysRequired(nums: IntArray, maxSumAllowed: Long): Int {
        var currentSum = 0
        var splitsRequired = 1

        for (num in nums) {
            if (currentSum + num <= maxSumAllowed) {
                currentSum += num
            } else {
                splitsRequired++
                currentSum = num
            }
        }
        return splitsRequired
    }
}

PHP


Python

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, right = max(nums), 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

Rust


Swift

class Solution {
    func splitArray(_ nums: [Int], _ m: Int) -> Int {
        var minLargetSplitSum = 0
        var left = nums.max()!
        var right = nums.reduce(0, +)
        while left <= right {
            let maxSumAllowed = (left + right) / 2

            if minSubarraysRequired(nums, maxSumAllowed) <= m{
                right = maxSumAllowed - 1
                minLargetSplitSum = maxSumAllowed
            } else {
                left = maxSumAllowed + 1
            }
        }

        return minLargetSplitSum
    }

    func minSubarraysRequired(_ nums: [Int], _ max_sum_allowed: Int) -> Int {
        var currentSum = 0
        var splitsRequired = 0

        for num in nums {
            if currentSum + num <= max_sum_allowed {
                currentSum += num
            } else {
                currentSum = num
                splitsRequired += 1
            }
        }

        return splitsRequired + 1
    }
}

Did you find this article valuable?

Support 攻城獅 by becoming a sponsor. Any amount is appreciated!