[Leetcode] 410. Split Array Largest Sum 解题报告

来源:互联网 发布:视频特效软件有哪些 编辑:程序博客网 时间:2024/05/20 22:37

题目

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:
If n is the length of array, assume the following constraints are satisfied:

  • 1 ≤ n ≤ 1000
  • 1 ≤ m ≤ min(50, n)

Examples:

Input:nums = [7,2,5,10,8]m = 2Output:18Explanation: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.

思路

我一开始直觉这道题目可以用动态规划来求解,可是发现无论时间复杂度还是空间复杂度都高达O(n^3),不是一个好的方法。后来在网上发现用二分查找法求解本题十分巧妙,解释如下:

我们直接要求这个最小值是比较困难的,但是给定一个值x,判断是否存在一种划分,使得每个子区间的和都不超过x,则是容易的。我们可以贪心地遍历一遍数组,不断求和,直到和超过了x值,再新分出一个子区间,最后检查划分出来的子区间数是否超过了m。这个检查的时间复杂度仅为O(n)。

然后就可以不断地判断x是否满足上述条件,如果满足说明我们要求的解不超过x,否则说明要求的解大于x,这就构成了一个二分查找的条件。那么x的取值范围可能是什么呢?其最小值显然是数组中元素的最大值,而最大值显然是数组中所有元素之和。接下来,一切都顺理成章了^_^。

假设数组中的元素个数是n,元素之和是m,则算法的时间复杂度是O(nlogm),其空间复杂度仅为O(1)。

代码

class Solution {public:    int splitArray(vector<int>& nums, int m) {        long long left = 0, right = 0;        for (int i = 0; i < nums.size(); ++i) {            left = max(left, (long long)nums[i]);       // the possible minimal value            right += nums[i];                           // the possible maximal value        }        while (left <= right) {            long long mid = left + (right - left) / 2;            if (valid(nums, m - 1, mid)) {                right = mid - 1;            }            else {                left = mid + 1;            }        }        return left;    }private:    bool valid(const vector<int> &nums, int cuts, long long max_value) {        int acc = 0;        for (int i = 0; i < nums.size(); ++i) {            if (nums[i] > max_value) {                return false;            }            else if (acc + nums[i] <= max_value) {                acc += nums[i];            }            else {                --cuts;                acc = nums[i];                if (cuts < 0) {                    return false;                }            }        }        return true;    }};

原创粉丝点击