(Source) Given an array 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.
Note:
Given m satisfies the following constraint: 1 ≤ m ≤ length(nums) ≤ 14,000.
Examples:
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.
Tags: Binary Search, Dynamic Programming
.
首先想到的是用动态规划来解决。用dp[i][j] (zero-based indices)
表示子问题:“把nums[0 : i + 1]
划分成j + 1
个连续非空子数组时,使得这些子数组分别的和的最大值最小化”的解。
class Solution(object):
def splitArray(self, nums, m):
"""
:type nums: List[int]
:type m: int
:rtype: int
"""
n = len(nums)
prefix_sum = [x for x in nums]
for i in xrange(1, n):
prefix_sum[i] += prefix_sum[i-1]
dp = [[0 for j in xrange(m)] for i in xrange(n)]
for i in xrange(n):
dp[i][0] = prefix_sum[i]
for j in xrange(1, m):
for i in xrange(n):
dp[i][j] = float('inf')
for k in xrange(j - 1, i + 1):
dp[i][j] = min(dp[i][j], max(dp[k][j-1], prefix_sum[i] - prefix_sum[k]))
return dp[-1][-1]
But, TLE…(:
class Solution(object):
def splitArray(self, nums, m):
"""
:type nums: List[int]
:type m: int
:rtype: int
"""
l, r = max(nums), sum(nums)
while l <= r:
mid = (l + r) >> 1
if self.validate(nums, m, mid):
r = mid - 1
else:
l = mid + 1
return l
def validate(self, nums, m, res):
"""Validate if nums can be splited into m non-empty continuous
subarrays with the largest sum among these m subarrays no more
than res
:type nums: List[int]
:type m: int
:type res: int
:rtype: boolean
"""
count, total = 1, 0
for i in xrange(len(nums)):
total += nums[i]
if total > res:
total = nums[i]
count += 1
if count > m:
return False
return True
References:
(1) https://discuss.leetcode.com/topic/61324/clear-explanation-8ms-binary-search-java
Complexity Analysis: TODO