1. 程式人生 > 其它 >1711 將陣列分成三個子陣列的方案數

1711 將陣列分成三個子陣列的方案數

技術標籤:LeetCode

題目描述:
我們稱一個分割整數陣列的方案是 好的 ,當它滿足:
陣列被分成三個 非空 連續子陣列,從左至右分別命名為 left , mid , right 。
left 中元素和小於等於 mid 中元素和,mid 中元素和小於等於 right 中元素和。
給你一個 非負 整數陣列 nums ,請你返回 好的 分割 nums 方案數目。由於答案可能會很大,請你將結果對 109 + 7 取餘後返回。

示例 1:
輸入:nums = [1,1,1]
輸出:1
解釋:唯一一種好的分割方案是將 nums 分成 [1] [1] [1] 。

示例 2:
輸入:nums = [1,2,2,2,5,0]

輸出:3
解釋:nums 總共有 3 種好的分割方案:
[1] [2] [2,2,5,0]
[1] [2,2] [2,5,0]
[1,2] [2,2] [5,0]

示例 3:
輸入:nums = [3,2,1]
輸出:0
解釋:沒有好的分割方案。

提示:
3 <= nums.length <= 105
0 <= nums[i] <= 104

方法1:
主要思路:解題彙總連結
(1)字首和+二分;
(2)先統計出原陣列的字首和;
(3)固定左邊的子陣列,再使用二分,找出滿足要求的中間陣列中,中間陣列的右邊界最小的取值;
(4)再使用二分,找出滿足要求的中間陣列中,中間陣列的右邊界最大的取值;

(5)該取值範圍就是當前固定左陣列前提下,可以獲得方案數;

class Solution {
public:
    int waysToSplit(vector<int>& nums) {
        int len=nums.size();
        vector<long long> sum_sub(len+1,0);
        long long res=0;
        for(int i=0;i<len;++i){//統計字首和
            sum_sub[i+1]=nums[i]+sum_sub[i];
        }
int end_sum=sum_sub.back()/3;//按照三個陣列的關係,則左陣列的最大和 for(int i=1;i<len;++i){ if(sum_sub[i]>end_sum){//超過該值,則不可能有滿足要求 的方案 break; } //統計出中間陣列的右邊界的最小值 int left=i+1,right=len;// while(left<right){ int mid=left+(right-left)/2; if(sum_sub[i]>sum_sub[mid]-sum_sub[i]){ left=mid+1; } else{ right=mid; } } int split1=right; //找出滿足要求的中間陣列的右邊界的最大取值 left=split1; right=len; while(left<right){ int mid=left+(right-left)/2; if(sum_sub[mid]-sum_sub[i]<=sum_sub[len]-sum_sub[mid]){ left=mid+1; } else{ right=mid; } } int split2=left-1; //當前方案數 res+=split2-split1+1; res%=1000000007; } return res%1000000007; } };