LeetCode 分割数组的最大值(二分搜索)

给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组。设计一个算法使得这 m 个子数组各自和的最大值最小。

注意:

数组长度 n 满足以下条件:
1 ≤ n ≤ 1000
1 ≤ m ≤ min(50, n)

示例:

输入:
nums = [7,2,5,10,8]
m = 2
输出:
18
解释:
一共有四种方法将nums分割为2个子数组。
其中最好的方式是将其分为[7,2,5] 和 [10,8],
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

思路分析:首先我们需要两种特殊情况,如果将大区间分为n个子区间(n为大区间元素的个数),此时子区间和的最大值的为最大元素的值left,因为每一个元素放一个区间。如果将大区间分为一个子区间,此时子区间的和的最大值为整个大区间的和right。然后我们使用二分法,每次折中mid = (left + right) / 2,看在折中的情况下需要分多少个子区间,如果需要分的子区间个数大于m,则说明我们给定的区间和的值小了,然后取高端[mid + 1, right],继续二分。否则取低端[left, mid]继续二分。

class Solution {
public:
	int splitArray(vector<int>& nums, int m) {
		long long left = 0, right = 0;//在[left, right]区间二分法搜索,每个区间段的最大和
        //left初始化为最大的单个元素,因为一个区间至少放一个元素,所以(区间段的最大和)的最小值为单个元素最值
        //right初始化为所有元素的和,因为最大的区间为尾初始大区间,(区间段的最大和)为所有元素的和
		for (auto num : nums) {
			left = max(left, (long long)num);
			right += num;
		}
        //二分法搜索
		while (left < right) {
            //mid为正在搜索的区间的和的期望值,need为这种分割的条件下子区间个数,cur为当前正在划分的区间已经放入的值的和
			long long mid = (left + right) / 2, need = 1, cur = 0;
			for (auto num : nums) {
                //确定在每个区间和不超过mid的情况下,需要分割子区间的个数
				if (cur + num > mid) {
                    //超过了当前正在划分的区间的最大和的期望值,需要再开一个子区间
					need += 1;
					cur = 0;//新开的子区间元素和清零
				}
				cur += num;
			}
			if (need > m) {
                //如果需要开的子区间数大于m,则说明区间和的期望值取小了
				left = mid + 1;
			}
			else {
                //否则说明可能取大了,也可能说明正好合适
				right = mid;
			}
		}
		return left;
	}
};

LeetCode 分割数组的最大值(二分搜索)_第1张图片

你可能感兴趣的:(LeetCode)