55
55
56
56
<!-- 这里可写通用的实现逻辑 -->
57
57
58
- ** 方法一:双指针 + 二分查找**
58
+ ** 方法一:前缀和 + 二分查找**
59
59
60
- 计算数组 ` nums ` 的前缀和 ` s ` 。由于 ` nums [i]` 是非负整数,可以得知 ` s ` 是一个单调递增数组 。
60
+ 我们先预处理出数组 ` nums ` 的前缀和数组 $s$,其中 $s [ i] $ 表述数组 ` nums ` 前 $i+1$ 个元素之和 。
61
61
62
- 我们枚举 ` left ` 子数组所能到达的下标,记为 ` i ` 。然后二分查找 ` mid ` 子数组分割的合理范围,记为 ` [j0, j1) ` ,累加方案数 ` j1-j0 ` 。注意答案取模操作 。
62
+ 由于数组 ` nums ` 的元素都是非负整数,因此前缀和数组 $s$ 是一个单调递增数组 。
63
63
64
- 时间复杂度 $O(n\log n)$,空间复杂度 $O(n)$,其中 $n$ 是数组的长度。
64
+ 我们在 $[ 0,..n-2)$ 的范围内枚举 ` left ` 子数组所能到达的下标 $i$,然后利用前缀和数组单调递增的特性,通过二分查找的方式找到 ` mid ` 子数组分割的合理范围,记为 $[ j, k)$,累加方案数 $k-j$。
65
+
66
+ 二分细节上,子数组分割必须满足 $s[ j] \geq s[ i] $,并且 $s[ n - 1] - s[ k] \geq s[ k] - s[ i] $。即 $s[ j] \geq s[ i] $,且 $s[ k] \leq \frac{s[ n - 1] + s[ i] }{2}$。
67
+
68
+ 最后,将方案数对 $10^9+7$ 取模后返回即可。
69
+
70
+ 时间复杂度 $O(n\times \log n)$。其中 $n$ 为数组 ` nums ` 的长度。
65
71
66
72
<!-- tabs:start -->
67
73
@@ -76,9 +82,9 @@ class Solution:
76
82
s = list (accumulate(nums))
77
83
ans, n = 0 , len (nums)
78
84
for i in range (n - 2 ):
79
- j0 = bisect_left(s, s[i] * 2 , i + 1 , n - 1 )
80
- j1 = bisect_right(s, (s[- 1 ] + s[i]) // 2 , j0 , n - 1 )
81
- ans += j1 - j0
85
+ j = bisect_left(s, s[i] << 1 , i + 1 , n - 1 )
86
+ k = bisect_right(s, (s[- 1 ] + s[i]) >> 1 , j , n - 1 )
87
+ ans += k - j
82
88
return ans % mod
83
89
```
84
90
@@ -99,14 +105,14 @@ class Solution {
99
105
}
100
106
int ans = 0 ;
101
107
for (int i = 0 ; i < n - 2 ; ++ i) {
102
- int j0 = lowerBound (s, s[i] * 2 , i + 1 , n - 1 );
103
- int j1 = lowerBound (s, (s[i ] + s[n - 1 ]) / 2 + 1 , j0 , n - 1 );
104
- ans = (ans + j1 - j0 ) % MOD ;
108
+ int j = search (s, s[i] << 1 , i + 1 , n - 1 );
109
+ int k = search (s, ((s[n - 1 ] + s[i]) >> 1 ) + 1 , j , n - 1 );
110
+ ans = (ans + k - j ) % MOD ;
105
111
}
106
112
return ans;
107
113
}
108
114
109
- private int lowerBound (int [] s , int x , int left , int right ) {
115
+ private int search (int [] s , int x , int left , int right ) {
110
116
while (left < right) {
111
117
int mid = (left + right) >> 1 ;
112
118
if (s[mid] >= x) {
@@ -125,55 +131,78 @@ class Solution {
125
131
``` cpp
126
132
class Solution {
127
133
public:
134
+ const int mod = 1e9 + 7;
135
+
128
136
int waysToSplit(vector<int>& nums) {
129
137
int n = nums.size();
130
138
vector<int> s(n, nums[0]);
131
139
for (int i = 1; i < n; ++i) s[i] = s[i - 1] + nums[i];
132
140
int ans = 0;
133
- int mod = 1e9 + 7;
134
141
for (int i = 0; i < n - 2; ++i) {
135
- int j0 = lower_bound(s.begin() + i + 1, s.begin() + n - 1, s[ i] * 2 ) - s.begin();
136
- int j1 = upper_bound(s.begin() + j0 , s.begin() + n - 1, (s[ i ] + s[ n - 1 ] ) / 2 ) - s.begin();
137
- ans = (ans + j1 - j0 ) % mod;
142
+ int j = lower_bound(s.begin() + i + 1, s.begin() + n - 1, s[i] << 1 ) - s.begin();
143
+ int k = upper_bound(s.begin() + j , s.begin() + n - 1, (s[n - 1 ] + s[i ]) >> 1 ) - s.begin();
144
+ ans = (ans + k - j ) % mod;
138
145
}
139
146
return ans;
140
147
}
141
148
};
142
149
```
143
150
144
- ### \*\*\*\ *
151
+ ### ** Go * *
145
152
146
153
``` go
147
- func waysToSplit(nums []int) int {
148
- search := func(s []int, x, left, right int) int {
149
- for left < right {
150
- mid := (left + right) >> 1
151
- if s[mid] >= x {
152
- right = mid
153
- } else {
154
- left = mid + 1
155
- }
156
- }
157
- return left
158
- }
159
- var mod int = 1e9 + 7
154
+ func waysToSplit (nums []int ) (ans int ) {
155
+ const mod int = 1e9 + 7
160
156
n := len (nums)
161
157
s := make ([]int , n)
162
158
s[0 ] = nums[0 ]
163
159
for i := 1 ; i < n; i++ {
164
160
s[i] = s[i-1 ] + nums[i]
165
161
}
166
- ans := 0
167
162
for i := 0 ; i < n-2 ; i++ {
168
- j0 := search(s, s[i]*2, i+1, n-1 )
169
- j1 := search(s, (s[i]+ s[n-1])/2+1, j0, n-1 )
170
- ans += j1 - j0
163
+ j := sort. Search (n- 1 , func (h int ) bool { return h > i && s[h] >= (s[i]<< 1 ) } )
164
+ k := sort. Search (n- 1 , func (h int ) bool { return h >= j && s[h] > ( s[n-1 ]+s[i])>> 1 } )
165
+ ans = (ans + k - j) % mod
171
166
}
172
- ans %= mod
173
- return ans
167
+ return
174
168
}
175
169
```
176
170
171
+ ### ** JavaScript**
172
+
173
+ ``` js
174
+ /**
175
+ * @param {number[]} nums
176
+ * @return {number}
177
+ */
178
+ var waysToSplit = function (nums ) {
179
+ const mod = 1e9 + 7 ;
180
+ const n = nums .length ;
181
+ const s = new Array (n).fill (nums[0 ]);
182
+ for (let i = 1 ; i < n; ++ i) {
183
+ s[i] = s[i - 1 ] + nums[i];
184
+ }
185
+ function search (s , x , left , right ) {
186
+ while (left < right) {
187
+ const mid = (left + right) >> 1 ;
188
+ if (s[mid] >= x) {
189
+ right = mid;
190
+ } else {
191
+ left = mid + 1 ;
192
+ }
193
+ }
194
+ return left;
195
+ }
196
+ let ans = 0 ;
197
+ for (let i = 0 ; i < n - 2 ; ++ i) {
198
+ const j = search (s, s[i] << 1 , i + 1 , n - 1 );
199
+ const k = search (s, ((s[n - 1 ] + s[i]) >> 1 ) + 1 , j, n - 1 );
200
+ ans = (ans + k - j) % mod;
201
+ }
202
+ return ans;
203
+ };
204
+ ```
205
+
177
206
### ** ...**
178
207
179
208
```
0 commit comments