Skip to content

Commit 6d6dbe4

Browse files
committed
feat: add solutions to lc problem: No.1712
No.1712.Ways to Split Array Into Three Subarrays
1 parent b820022 commit 6d6dbe4

File tree

7 files changed

+166
-96
lines changed

7 files changed

+166
-96
lines changed

solution/1700-1799/1712.Ways to Split Array Into Three Subarrays/README.md

+64-35
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,19 @@
5555

5656
<!-- 这里可写通用的实现逻辑 -->
5757

58-
**方法一:双指针 + 二分查找**
58+
**方法一:前缀和 + 二分查找**
5959

60-
计算数组 `nums` 的前缀和 `s`。由于 `nums[i]` 是非负整数,可以得知 `s` 是一个单调递增数组
60+
我们先预处理出数组 `nums` 的前缀和数组 $s$,其中 $s[i]$ 表述数组 `nums` 前 $i+1$ 个元素之和
6161

62-
我们枚举 `left` 子数组所能到达的下标,记为 `i`。然后二分查找 `mid` 子数组分割的合理范围,记为 `[j0, j1)`,累加方案数 `j1-j0`。注意答案取模操作
62+
由于数组 `nums` 的元素都是非负整数,因此前缀和数组 $s$ 是一个单调递增数组
6363

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` 的长度。
6571

6672
<!-- tabs:start -->
6773

@@ -76,9 +82,9 @@ class Solution:
7682
s = list(accumulate(nums))
7783
ans, n = 0, len(nums)
7884
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
8288
return ans % mod
8389
```
8490

@@ -99,14 +105,14 @@ class Solution {
99105
}
100106
int ans = 0;
101107
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;
105111
}
106112
return ans;
107113
}
108114

109-
private int lowerBound(int[] s, int x, int left, int right) {
115+
private int search(int[] s, int x, int left, int right) {
110116
while (left < right) {
111117
int mid = (left + right) >> 1;
112118
if (s[mid] >= x) {
@@ -125,55 +131,78 @@ class Solution {
125131
```cpp
126132
class Solution {
127133
public:
134+
const int mod = 1e9 + 7;
135+
128136
int waysToSplit(vector<int>& nums) {
129137
int n = nums.size();
130138
vector<int> s(n, nums[0]);
131139
for (int i = 1; i < n; ++i) s[i] = s[i - 1] + nums[i];
132140
int ans = 0;
133-
int mod = 1e9 + 7;
134141
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;
138145
}
139146
return ans;
140147
}
141148
};
142149
```
143150

144-
### \*\*\*\*
151+
### **Go**
145152

146153
```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
160156
n := len(nums)
161157
s := make([]int, n)
162158
s[0] = nums[0]
163159
for i := 1; i < n; i++ {
164160
s[i] = s[i-1] + nums[i]
165161
}
166-
ans := 0
167162
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
171166
}
172-
ans %= mod
173-
return ans
167+
return
174168
}
175169
```
176170

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+
177206
### **...**
178207

179208
```

solution/1700-1799/1712.Ways to Split Array Into Three Subarrays/README_EN.md

+54-31
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ class Solution:
6060
s = list(accumulate(nums))
6161
ans, n = 0, len(nums)
6262
for i in range(n - 2):
63-
j0 = bisect_left(s, s[i] * 2, i + 1, n - 1)
64-
j1 = bisect_right(s, (s[-1] + s[i]) // 2, j0, n - 1)
65-
ans += j1 - j0
63+
j = bisect_left(s, s[i] << 1, i + 1, n - 1)
64+
k = bisect_right(s, (s[-1] + s[i]) >> 1, j, n - 1)
65+
ans += k - j
6666
return ans % mod
6767
```
6868

@@ -81,14 +81,14 @@ class Solution {
8181
}
8282
int ans = 0;
8383
for (int i = 0; i < n - 2; ++i) {
84-
int j0 = lowerBound(s, s[i] * 2, i + 1, n - 1);
85-
int j1 = lowerBound(s, (s[i] + s[n - 1]) / 2 + 1, j0, n - 1);
86-
ans = (ans + j1 - j0) % MOD;
84+
int j = search(s, s[i] << 1, i + 1, n - 1);
85+
int k = search(s, ((s[n - 1] + s[i]) >> 1) + 1, j, n - 1);
86+
ans = (ans + k - j) % MOD;
8787
}
8888
return ans;
8989
}
9090

91-
private int lowerBound(int[] s, int x, int left, int right) {
91+
private int search(int[] s, int x, int left, int right) {
9292
while (left < right) {
9393
int mid = (left + right) >> 1;
9494
if (s[mid] >= x) {
@@ -107,55 +107,78 @@ class Solution {
107107
```cpp
108108
class Solution {
109109
public:
110+
const int mod = 1e9 + 7;
111+
110112
int waysToSplit(vector<int>& nums) {
111113
int n = nums.size();
112114
vector<int> s(n, nums[0]);
113115
for (int i = 1; i < n; ++i) s[i] = s[i - 1] + nums[i];
114116
int ans = 0;
115-
int mod = 1e9 + 7;
116117
for (int i = 0; i < n - 2; ++i) {
117-
int j0 = lower_bound(s.begin() + i + 1, s.begin() + n - 1, s[i] * 2) - s.begin();
118-
int j1 = upper_bound(s.begin() + j0, s.begin() + n - 1, (s[i] + s[n - 1]) / 2) - s.begin();
119-
ans = (ans + j1 - j0) % mod;
118+
int j = lower_bound(s.begin() + i + 1, s.begin() + n - 1, s[i] << 1) - s.begin();
119+
int k = upper_bound(s.begin() + j, s.begin() + n - 1, (s[n - 1] + s[i]) >> 1) - s.begin();
120+
ans = (ans + k - j) % mod;
120121
}
121122
return ans;
122123
}
123124
};
124125
```
125126
126-
### \*\*\*\*
127+
### **Go**
127128
128129
```go
129-
func waysToSplit(nums []int) int {
130-
search := func(s []int, x, left, right int) int {
131-
for left < right {
132-
mid := (left + right) >> 1
133-
if s[mid] >= x {
134-
right = mid
135-
} else {
136-
left = mid + 1
137-
}
138-
}
139-
return left
140-
}
141-
var mod int = 1e9 + 7
130+
func waysToSplit(nums []int) (ans int) {
131+
const mod int = 1e9 + 7
142132
n := len(nums)
143133
s := make([]int, n)
144134
s[0] = nums[0]
145135
for i := 1; i < n; i++ {
146136
s[i] = s[i-1] + nums[i]
147137
}
148-
ans := 0
149138
for i := 0; i < n-2; i++ {
150-
j0 := search(s, s[i]*2, i+1, n-1)
151-
j1 := search(s, (s[i]+s[n-1])/2+1, j0, n-1)
152-
ans += j1 - j0
139+
j := sort.Search(n-1, func(h int) bool { return h > i && s[h] >= (s[i]<<1) })
140+
k := sort.Search(n-1, func(h int) bool { return h >= j && s[h] > (s[n-1]+s[i])>>1 })
141+
ans = (ans + k - j) % mod
153142
}
154-
ans %= mod
155-
return ans
143+
return
156144
}
157145
```
158146

147+
### **JavaScript**
148+
149+
```js
150+
/**
151+
* @param {number[]} nums
152+
* @return {number}
153+
*/
154+
var waysToSplit = function (nums) {
155+
const mod = 1e9 + 7;
156+
const n = nums.length;
157+
const s = new Array(n).fill(nums[0]);
158+
for (let i = 1; i < n; ++i) {
159+
s[i] = s[i - 1] + nums[i];
160+
}
161+
function search(s, x, left, right) {
162+
while (left < right) {
163+
const mid = (left + right) >> 1;
164+
if (s[mid] >= x) {
165+
right = mid;
166+
} else {
167+
left = mid + 1;
168+
}
169+
}
170+
return left;
171+
}
172+
let ans = 0;
173+
for (let i = 0; i < n - 2; ++i) {
174+
const j = search(s, s[i] << 1, i + 1, n - 1);
175+
const k = search(s, ((s[n - 1] + s[i]) >> 1) + 1, j, n - 1);
176+
ans = (ans + k - j) % mod;
177+
}
178+
return ans;
179+
};
180+
```
181+
159182
### **...**
160183

161184
```

solution/1700-1799/1712.Ways to Split Array Into Three Subarrays/Solution.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
class Solution {
22
public:
3+
const int mod = 1e9 + 7;
4+
35
int waysToSplit(vector<int>& nums) {
46
int n = nums.size();
57
vector<int> s(n, nums[0]);
68
for (int i = 1; i < n; ++i) s[i] = s[i - 1] + nums[i];
79
int ans = 0;
8-
int mod = 1e9 + 7;
910
for (int i = 0; i < n - 2; ++i) {
10-
int j0 = lower_bound(s.begin() + i + 1, s.begin() + n - 1, s[i] * 2) - s.begin();
11-
int j1 = upper_bound(s.begin() + j0, s.begin() + n - 1, (s[i] + s[n - 1]) / 2) - s.begin();
12-
ans = (ans + j1 - j0) % mod;
11+
int j = lower_bound(s.begin() + i + 1, s.begin() + n - 1, s[i] << 1) - s.begin();
12+
int k = upper_bound(s.begin() + j, s.begin() + n - 1, (s[n - 1] + s[i]) >> 1) - s.begin();
13+
ans = (ans + k - j) % mod;
1314
}
1415
return ans;
1516
}
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,15 @@
1-
func waysToSplit(nums []int) int {
2-
search := func(s []int, x, left, right int) int {
3-
for left < right {
4-
mid := (left + right) >> 1
5-
if s[mid] >= x {
6-
right = mid
7-
} else {
8-
left = mid + 1
9-
}
10-
}
11-
return left
12-
}
13-
var mod int = 1e9 + 7
1+
func waysToSplit(nums []int) (ans int) {
2+
const mod int = 1e9 + 7
143
n := len(nums)
154
s := make([]int, n)
165
s[0] = nums[0]
176
for i := 1; i < n; i++ {
187
s[i] = s[i-1] + nums[i]
198
}
20-
ans := 0
219
for i := 0; i < n-2; i++ {
22-
j0 := search(s, s[i]*2, i+1, n-1)
23-
j1 := search(s, (s[i]+s[n-1])/2+1, j0, n-1)
24-
ans += j1 - j0
10+
j := sort.Search(n-1, func(h int) bool { return h > i && s[h] >= (s[i]<<1) })
11+
k := sort.Search(n-1, func(h int) bool { return h >= j && s[h] > (s[n-1]+s[i])>>1 })
12+
ans = (ans + k - j) % mod
2513
}
26-
ans %= mod
27-
return ans
14+
return
2815
}

solution/1700-1799/1712.Ways to Split Array Into Three Subarrays/Solution.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ public int waysToSplit(int[] nums) {
1010
}
1111
int ans = 0;
1212
for (int i = 0; i < n - 2; ++i) {
13-
int j0 = lowerBound(s, s[i] * 2, i + 1, n - 1);
14-
int j1 = lowerBound(s, (s[i] + s[n - 1]) / 2 + 1, j0, n - 1);
15-
ans = (ans + j1 - j0) % MOD;
13+
int j = search(s, s[i] << 1, i + 1, n - 1);
14+
int k = search(s, ((s[n - 1] + s[i]) >> 1) + 1, j, n - 1);
15+
ans = (ans + k - j) % MOD;
1616
}
1717
return ans;
1818
}
1919

20-
private int lowerBound(int[] s, int x, int left, int right) {
20+
private int search(int[] s, int x, int left, int right) {
2121
while (left < right) {
2222
int mid = (left + right) >> 1;
2323
if (s[mid] >= x) {

0 commit comments

Comments
 (0)