可以在答案集上二分,枚舉不同的答案,然後查看是否可以分割成m塊。由於是求subarray,對於能否以某一和進行分割只需要花O(n)的時間,所以時間複雜度是 Nlog(sum)。
int binarySearch(int sum, vector<int> nums, m){
int l = 0, r = sum;
while(l <= r){
int mid = (l + r) /2;
if(check(mid, nums, m))l = mid + 1;
else r = mid - 1;
}
return l;
}
對於二分直接套用模板,我具體分析什麼時候應該把答案往大的推,什麼時候把答案留在left,什麼時候把答案往小的推。
首先,如果發現某一個答案可以分割成m 或者大於m,就是說他的答案可以再大一點,所以往大的推,check這時候要return true。
其次,如果發現不能分割成每一段的和至少為 mid,我們就往小的推,這時候check return false。
最後,我們要保證我們的mid大於所有num的元素,因為我們的left至少要是num的最大值,不然對於,長度為m,要分割m段時,會出錯。
bool check(int mid, vector<int> nums, int m){
int cnt = 0, temp = 0;
for(auto a : nums){
temp += a;
if(temp > mid){
cnt++;
temp = a;
}
if(a > mid)return 1;
}
return cnt >= m;
}
P.S 一段subarray的和要大於mid才能對cnt有貢獻,因為如果等於也有貢獻的話,subarray的和不可以大於mid,所以我們temp是直接把超過的那一個位置當成下一個array的開始。
class Solution {
public:
bool isValid(int mid, int m, vector<int> nums){
int temp = 0, cnt = 0;
for(int a : nums){
temp += a;
if(temp > mid){
cnt++;
temp = a;
}
if(a > mid)return 1;
}
return cnt >= m;
}
int binarySearch(int sum, int m, vector<int> nums){
int l = 0, r = sum;
while(l <= r){
int mid = (l + r) / 2;
if(isValid(mid, m, nums)){l = mid + 1;}
else r = mid - 1;
}
return l;
}
int splitArray(vector<int>& nums, int m) {
int totSum = 0; for(auto a : nums){totSum += a;}
return binarySearch(totSum, m, nums);
}
};