题目:
给定一个非负整数数组 nums 和一个整数 m ,你需要将这个数组分成 m 个非空的连续子数组。
设计一个算法使得这 m 个子数组各自和的最大值最小。
示例 1:
输入:nums = [7,2,5,10,8], m = 2
输出:18
解释:
一共有四种方法将 nums 分割为 2 个子数组。
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。
示例 2:
输入:nums = [1,2,3,4,5], m = 2
输出:9
示例 3:
输入:nums = [1,4,4], m = 3
输出:4
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 106
1 <= m <= min(50, nums.length)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/split-array-largest-sum
思路:
1. 先遍历数组 nums ,从中找到最大的元素,记做 maxNum; 遍历求所有元素的和,记做 sumNum。 (则要求的这 m 个子数组各自和的最大值最小一定在 maxNum 到 sumNum 之间) 2. 定义函数 splitNums,该函数的作用是返回能将数组 nums 按照子数组和不超过 maxSum 时,可以分成的子数组的个数。 3. 按照二分法遍历 maxNum 到 sumNum 之间 的数, 1)left = maxNum, right = sumNum 2) mid = left + (right - left) / 2 3) 若是 splitNums(nums,mid) > m ,说明 按照子数组和不超过 mid 的原则分数组nums,得到的子数组过多,即 mid 过小,此时移动左边界:left = mid + 1 若是 splitNums(nums,mid) <= m ,说明 按照子数组和不超过 mid 的原则分数组nums,得到的子数组过少,即 mid 过大,此时移动右边界:right = mid 4)重复 2) 与 3) 步骤,直到 left 与 right相等为止。
java代码如下:
class Solution {
public int splitArray(int[] nums, int m) {
int maxNum = 0;
int sumNum = 0;
for (int num : nums) {
maxNum = Math.max(maxNum, num);
sumNum += num;
}
int left = maxNum;
int right = sumNum;
while (left < right) {
int mid = left + (right - left) / 2;
if (splitNums(nums, mid) > m) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
int splitNums(int[] nums, int maxSum) {
int currentSum = 0;
int count = 1;
for (int num : nums) {
if (currentSum + num > maxSum) {
count++;
currentSum = 0;
}
currentSum += num;
}
return count;
}
}
c++
class Solution {
public:
int splitArray(vector<int>& nums, int k) {
int sum = 0;
int maxNum = 0;
for(int num: nums) {
sum += num;
maxNum = max(maxNum, num);
}
// 每个子数组和的最大值最小值 一定在 [maxNum, sum] 之间
// 闭开区间二分法查找
int left = maxNum;
int right = sum + 1;
while(left < right) {
int mid = left + (right-left)/2;
int m = splitNums(nums, mid);
if(m == k) {
right = mid;
} else if(m < k) {
right = mid;
} else if(m > k) {
left = left + 1;
}
}
return right;
}
int splitNums(vector<int>& nums, int maxSum) {
int result = 1;
int sum = 0;
for(int a:nums) {
if(sum + a <= maxSum) {
sum += a;
} else {
sum = a;
result += 1;
}
}
return result;
}
};