50
50
51
51
<!-- 这里可写通用的实现逻辑 -->
52
52
53
- 二分查找。
53
+ ** 方法一: 二分查找**
54
54
55
- 二分枚举** 子数组的和的最大值** ,找到满足条件的最小值。
55
+ 我们注意到,当子数组的和的最大值越大,子数组的个数越少,当存在一个满足条件的子数组和的最大值时,那么比这个最大值更大的子数组和的最大值一定也满足条件。也就是说,我们可以对子数组和的最大值进行二分查找,找到满足条件的最小值。
56
+
57
+ 我们定义二分查找的左边界 $left = max(nums)$,右边界 $right = sum(nums)$,然后对于二分查找的每一步,我们取中间值 $mid = (left + right) / 2$,然后判断是否存在一个分割方式,使得子数组的和的最大值不超过 $mid$,如果存在,则说明 $mid$ 可能是满足条件的最小值,因此我们将右边界调整为 $mid$,否则我们将左边界调整为 $mid + 1$。
58
+
59
+ 我们如何判断是否存在一个分割方式,使得子数组的和的最大值不超过 $mid$ 呢?我们可以使用贪心的方法,从左到右遍历数组,将数组中的元素依次加入到子数组中,如果当前子数组的和大于 $mid$,则我们将当前元素加入到下一个子数组中。如果我们能够将数组分割成不超过 $k$ 个子数组,且每个子数组的和的最大值不超过 $mid$,则说明 $mid$ 是满足条件的最小值,否则 $mid$ 不是满足条件的最小值。
60
+
61
+ 时间复杂度 $O(n \times \log m),空间复杂度 O(1)$。其中 $n$ 和 $m$ 分别是数组的长度和数组所有元素的和。
56
62
57
63
<!-- tabs:start -->
58
64
62
68
63
69
``` python
64
70
class Solution :
65
- def splitArray (self , nums : List[int ], m : int ) -> int :
66
- def check (x ):
67
- s, cnt = 0 , 1
68
- for num in nums:
69
- if s + num > x:
71
+ def splitArray (self , nums : List[int ], k : int ) -> int :
72
+ def check (mx ):
73
+ s, cnt = inf, 0
74
+ for x in nums:
75
+ s += x
76
+ if s > mx:
77
+ s = x
70
78
cnt += 1
71
- s = num
72
- else :
73
- s += num
74
- return cnt <= m
79
+ return cnt <= k
75
80
76
81
left, right = max (nums), sum (nums)
77
- while left < right:
78
- mid = (left + right) >> 1
79
- if check(mid):
80
- right = mid
81
- else :
82
- left = mid + 1
83
- return left
82
+ return left + bisect_left(range (left, right + 1 ), True , key = check)
84
83
```
85
84
86
85
### ** Java**
@@ -89,15 +88,15 @@ class Solution:
89
88
90
89
``` java
91
90
class Solution {
92
- public int splitArray (int [] nums , int m ) {
93
- int mx = - 1 ;
94
- for (int num : nums) {
95
- mx = Math . max(mx, num);
91
+ public int splitArray (int [] nums , int k ) {
92
+ int left = 0 , right = 0 ;
93
+ for (int x : nums) {
94
+ left = Math . max(left, x);
95
+ right += x;
96
96
}
97
- int left = mx, right = (int ) 1e9 ;
98
97
while (left < right) {
99
98
int mid = (left + right) >> 1 ;
100
- if (check(nums, m, mid )) {
99
+ if (check(nums, mid, k )) {
101
100
right = mid;
102
101
} else {
103
102
left = mid + 1 ;
@@ -106,17 +105,16 @@ class Solution {
106
105
return left;
107
106
}
108
107
109
- private boolean check (int [] nums , int m , int x ) {
110
- int s = 0 , cnt = 1 ;
111
- for (int num : nums) {
112
- if (s + num > x) {
108
+ private boolean check (int [] nums , int mx , int k ) {
109
+ int s = 1 << 30 , cnt = 0 ;
110
+ for (int x : nums) {
111
+ s += x;
112
+ if (s > mx) {
113
113
++ cnt;
114
- s = num;
115
- } else {
116
- s += num;
114
+ s = x;
117
115
}
118
116
}
119
- return cnt <= m ;
117
+ return cnt <= k ;
120
118
}
121
119
}
122
120
```
@@ -126,29 +124,32 @@ class Solution {
126
124
``` cpp
127
125
class Solution {
128
126
public:
129
- int splitArray(vector<int >& nums, int m) {
130
- int left = * max_element(nums.begin(), nums.end()), right = (int)1e9;
127
+ int splitArray(vector<int >& nums, int k) {
128
+ int left = 0, right = 0;
129
+ for (int& x : nums) {
130
+ left = max(left, x);
131
+ right += x;
132
+ }
133
+ auto check = [ &] (int mx) {
134
+ int s = 1 << 30, cnt = 0;
135
+ for (int& x : nums) {
136
+ s += x;
137
+ if (s > mx) {
138
+ s = x;
139
+ ++cnt;
140
+ }
141
+ }
142
+ return cnt <= k;
143
+ };
131
144
while (left < right) {
132
- int mid = left + right >> 1;
133
- if (check(nums, m, mid))
145
+ int mid = ( left + right) >> 1;
146
+ if (check(mid)) {
134
147
right = mid;
135
- else
136
- left = mid + 1;
137
- }
138
- return left;
139
- }
140
-
141
- bool check(vector<int>& nums, int m, int x) {
142
- int s = 0, cnt = 1;
143
- for (int num : nums) {
144
- if (s + num > x) {
145
- ++cnt;
146
- s = num;
147
148
} else {
148
- s += num ;
149
+ left = mid + 1 ;
149
150
}
150
151
}
151
- return cnt <= m ;
152
+ return left ;
152
153
}
153
154
};
154
155
```
@@ -157,33 +158,23 @@ public:
157
158
158
159
```go
159
160
func splitArray(nums []int, k int) int {
160
- mx := -1
161
- for _ , num := range nums {
162
- mx = max (mx, num)
161
+ left, right := 0, 0
162
+ for _, x := range nums {
163
+ left = max(left, x)
164
+ right += x
163
165
}
164
- left , right := mx, int (1e9 )
165
- for left < right {
166
- mid := (left + right) >> 1
167
- if check (nums, k, mid) {
168
- right = mid
169
- } else {
170
- left = mid + 1
166
+ return left + sort.Search(right-left, func(mx int) bool {
167
+ mx += left
168
+ s, cnt := 1<<30, 0
169
+ for _, x := range nums {
170
+ s += x
171
+ if s > mx {
172
+ s = x
173
+ cnt++
174
+ }
171
175
}
172
- }
173
- return left
174
- }
175
-
176
- func check (nums []int , k , x int ) bool {
177
- s , cnt := 0 , 1
178
- for _ , num := range nums {
179
- if s+num > x {
180
- cnt++
181
- s = num
182
- } else {
183
- s += num
184
- }
185
- }
186
- return cnt <= k
176
+ return cnt <= k
177
+ })
187
178
}
188
179
189
180
func max(a, b int) int {
@@ -194,6 +185,40 @@ func max(a, b int) int {
194
185
}
195
186
```
196
187
188
+ ### ** TypeScript**
189
+
190
+ ``` ts
191
+ function splitArray(nums : number [], k : number ): number {
192
+ let left = 0 ;
193
+ let right = 0 ;
194
+ for (const x of nums ) {
195
+ left = Math .max (left , x );
196
+ right += x ;
197
+ }
198
+ const check = (mx : number ) => {
199
+ let s = 1 << 30 ;
200
+ let cnt = 0 ;
201
+ for (const x of nums ) {
202
+ s += x ;
203
+ if (s > mx ) {
204
+ s = x ;
205
+ ++ cnt ;
206
+ }
207
+ }
208
+ return cnt <= k ;
209
+ };
210
+ while (left < right ) {
211
+ const mid = (left + right ) >> 1 ;
212
+ if (check (mid )) {
213
+ right = mid ;
214
+ } else {
215
+ left = mid + 1 ;
216
+ }
217
+ }
218
+ return left ;
219
+ }
220
+ ```
221
+
197
222
### ** ...**
198
223
199
224
```
0 commit comments