【LeetCode】410. Split Array Largest Sum

本文介绍了一种使用二分法来解决将数组分割成多个连续子序列,并使这些子序列各自和的最大值最小化的算法问题。通过具体示例说明了如何实现这一算法,并给出了完整的参考代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关键词:二分法


问题描述:

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.


即将一个数组分为m个连续的子序列,使m个子序列各自的和的最大值最小化。


解题思路:

记数组nums的和为su

在[0, su + 1)区间中进行二分,每次二分比较大小的函数为:判断中值是否能作为m份子序列的最大值。


首先回忆一下数组的二分法:

int lower_bound(vector<int> &a, int x){
	int lo = 0, hi = a.size();
	while(lo < hi){
		int mi = (lo + hi) >> 1;
		int v = a[mi]; 
		x <= v ? hi = mi : lo = mi + 1; 
	}
	return hi;
}

int upper_bound(vector<int> &a, int x){
	int lo = 0, hi = a.size();
	while(lo < hi){
		int mi = (lo + hi) >> 1;
		int v = a[mi]; 
		x < v ? hi = mi : lo = mi + 1; 
	}
	return --hi;
}

以lower_bound为例,[0, lo)为小于x的所有元素,[hi, n)为大于或等于x的所有元素。

在二分的过程中,这个约束没有改变。

二分法结束时,lo = hi。

要求得第一个大于或等于x的元素,根据约束可知,所求元素的位置为hi(lo).


以upper_bound为例,[0, lo)为小于或等于x的所有元素,[hi, n)为大于x的所有元素。

在二分的过程中,这个约束没有改变。

二分法结束时,lo = hi。

要求得最后一个小于或等于x的元素,根据约束可知,所求元素的位置为hi-1(lo-1).


在本问题中,使用的二分法与lower_bound相近。


参考代码:

class Solution {
public:
	bool check(vector<int> &nums, int m, long long q){
		long long s = 0;
		int use = 0;
		for (int i = 0; i < nums.size(); ++i){
			int h = nums[i];
			if (h > q)return false;
			if (s + h > q){
				++use;
				if (use >= m)return false;
				s = 0;
			}
		    s += h;
		}
		return true;
	}
    int splitArray(vector<int>& nums, int m) {
		long long su = 0;
		for (int h : nums)su += h;
		long long lo = 0;
		long long hi = su + 1;
		// [lo, hi)
		while (lo < hi){
			long long mi = (lo + hi) >> 1;
			if (check(nums, m, mi)){ // if (a[mi] <= x)
				// 可以更小
				hi = mi;
			}else{
				// 可以更大
				lo = mi + 1;
			}
		}
		return hi; 
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值