A split of an integer array is good if:
- The array is split into three non-empty contiguous subarrays - named
left
,mid
,right
respectively from left to right. - The sum of the elements in
left
is less than or equal to the sum of the elements inmid
, and the sum of the elements inmid
is less than or equal to the sum of the elements inright
.
Given nums
, an array of non-negative integers, return the number of good ways to split nums
. As the number may be too large, return it modulo 109 + 7
.
Example 1:
Input: nums = [1,1,1] Output: 1 Explanation: The only good way to split nums is [1] [1] [1].
Example 2:
Input: nums = [1,2,2,2,5,0] Output: 3 Explanation: There are three good ways of splitting nums: [1] [2] [2,2,5,0] [1] [2,2] [2,5,0] [1,2] [2,2] [5,0]
Example 3:
Input: nums = [3,2,1] Output: 0 Explanation: There is no good way to split nums.
Constraints:
3 <= nums.length <= 105
0 <= nums[i] <= 104
题目:给定一串数组,将数组分成三部分,第一部分总和小于等于第二部分,第二部分总和小于等于第三部分。问共有多少种分割方法。
思路:求总和,先将数组整体求和。每个元素点i都是前面0~i元素点的总和。然后从前往后遍历,先确定第一个子数组,找到第二个子数组和第三个子数组的最前和最后分割点,中间的差值加入到结果中。找分割点时用二分法,双指针的题中,lower_bound和upper_bound简直不要太好用哦~
代码:
class Solution {
public:
int waysToSplit(vector<int>& nums) {
for(int i = 1; i < nums.size(); i++){
nums[i] += nums[i-1];
}
int res = 0, total = nums.back(), mod = 1000000007;
for(int i = 0; i < nums.size()-2; i++){
if(nums[i] > total/3) return res;
int start = lower_bound(nums.begin()+i+1, nums.end(), 2*nums[i])-nums.begin();
int end = upper_bound(nums.begin()+start, nums.end(), (total+nums[i])/2)-nums.begin();
if(end == nums.size()) end--; //全零数组找upper_bound时会找到数组结尾,但第三个不能是空数组,所以需要减一。
res = (res - start + end) % mod;
}
return res;
}
};
time: O(N*logN), space:O(1);