@@ -83,60 +83,15 @@ tags:
83
83
84
84
### 方法一:二分查找
85
85
86
- 二分枚举速度值,找到满足条件的最小速度 。
86
+ 我们注意到,如果一个速度值 $v$ 能够使得我们在规定时间内到达,那么对于任意 $v' > v$,我们也一定能在规定时间内到达。这存在着单调性,因此我们可以使用二分查找,找到最小的满足条件的速度值 。
87
87
88
- 时间复杂度 $O(n\times \log m)$,其中 $n$ 和 $m$ 分别为数组 ` dist ` 和最大速度值 。
88
+ 我们可以二分枚举速度值,首先定义二分的左右边界为 $l = 1$, $r = 10^7 + 1$,然后我们每次取中间值 $\text{mid} = \frac{l + r}{2}$,判断是否满足条件。如果满足条件,我们将右边界移动到 $\text{mid}$,否则将左边界移动到 $\text{mid} + 1$ 。
89
89
90
- 以下是二分查找的两个通用模板:
90
+ 问题转化为判断一个速度值 $v$ 是否能够在规定时间内到达。我们可以遍历每一趟列车,计算每一趟列车的运行时间 $t = \frac{d}{v}$,如果是最后一趟列车,我们直接加上 $t$,否则我们向上取整加上 $t$。最后判断总时间是否小于等于规定时间,如果是则说明满足条件。
91
91
92
- 模板 1:
92
+ 二分结束后,如果左边界超过了 $10^7$,说明无法在规定时间内到达,返回 $-1$,否则返回左边界。
93
93
94
- ``` java
95
- boolean check(int x) {
96
- }
97
-
98
- int search(int left, int right) {
99
- while (left < right) {
100
- int mid = (left + right) >> 1 ;
101
- if (check(mid)) {
102
- right = mid;
103
- } else {
104
- left = mid + 1 ;
105
- }
106
- }
107
- return left;
108
- }
109
- ```
110
-
111
- 模板 2:
112
-
113
- ``` java
114
- boolean check(int x) {
115
- }
116
-
117
- int search(int left, int right) {
118
- while (left < right) {
119
- int mid = (left + right + 1 ) >> 1 ;
120
- if (check(mid)) {
121
- left = mid;
122
- } else {
123
- right = mid - 1 ;
124
- }
125
- }
126
- return left;
127
- }
128
- ```
129
-
130
- 做二分题目时,可以按照以下套路:
131
-
132
- 1 . 写出循环条件 $left < right$;
133
- 1 . 循环体内,不妨先写 $mid = \lfloor \frac{left + right}{2} \rfloor$;
134
- 1 . 根据具体题目,实现 $check()$ 函数(有时很简单的逻辑,可以不定义 $check$),想一下究竟要用 $right = mid$(模板 $1$) 还是 $left = mid$(模板 $2$);
135
- - 如果 $right = mid$,那么写出 else 语句 $left = mid + 1$,并且不需要更改 mid 的计算,即保持 $mid = \lfloor \frac{left + right}{2} \rfloor$;
136
- - 如果 $left = mid$,那么写出 else 语句 $right = mid - 1$,并且在 $mid$ 计算时补充 +1,即 $mid = \lfloor \frac{left + right + 1}{2} \rfloor$;
137
- 1 . 循环结束时,$left$ 与 $right$ 相等。
138
-
139
- 注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 $left$ 或者 $right$ 是否满足题意即可。
94
+ 时间复杂度 $O(n \times \log M)$,其中 $n$ 和 $M$ 分别为列车数量和速度的上界。空间复杂度 $O(1)$。
140
95
141
96
<!-- tabs:start -->
142
97
@@ -145,12 +100,15 @@ int search(int left, int right) {
145
100
``` python
146
101
class Solution :
147
102
def minSpeedOnTime (self , dist : List[int ], hour : float ) -> int :
148
- def check (speed ) :
149
- res = 0
103
+ def check (v : int ) -> bool :
104
+ s = 0
150
105
for i, d in enumerate (dist):
151
- res += (d / speed) if i == len (dist) - 1 else math.ceil(d / speed)
152
- return res <= hour
106
+ t = d / v
107
+ s += t if i == len (dist) - 1 else ceil(t)
108
+ return s <= hour
153
109
110
+ if len (dist) > ceil(hour):
111
+ return - 1
154
112
r = 10 ** 7 + 1
155
113
ans = bisect_left(range (1 , r), True , key = check) + 1
156
114
return - 1 if ans == r else ans
@@ -161,25 +119,30 @@ class Solution:
161
119
``` java
162
120
class Solution {
163
121
public int minSpeedOnTime (int [] dist , double hour ) {
164
- int left = 1 , right = (int ) 1e7 ;
165
- while (left < right) {
166
- int mid = (left + right) >> 1 ;
122
+ if (dist. length > Math . ceil(hour)) {
123
+ return - 1 ;
124
+ }
125
+ final int m = (int ) 1e7 ;
126
+ int l = 1 , r = m + 1 ;
127
+ while (l < r) {
128
+ int mid = (l + r) >> 1 ;
167
129
if (check(dist, mid, hour)) {
168
- right = mid;
130
+ r = mid;
169
131
} else {
170
- left = mid + 1 ;
132
+ l = mid + 1 ;
171
133
}
172
134
}
173
- return check(dist, left, hour) ? left : - 1 ;
135
+ return l > m ? - 1 : l ;
174
136
}
175
137
176
- private boolean check (int [] dist , int speed , double hour ) {
177
- double res = 0 ;
178
- for (int i = 0 ; i < dist. length; ++ i) {
179
- double cost = dist[i] * 1.0 / speed;
180
- res += (i == dist. length - 1 ? cost : Math . ceil(cost));
138
+ private boolean check (int [] dist , int v , double hour ) {
139
+ double s = 0 ;
140
+ int n = dist. length;
141
+ for (int i = 0 ; i < n; ++ i) {
142
+ double t = dist[i] * 1.0 / v;
143
+ s += i == n - 1 ? t : Math . ceil(t);
181
144
}
182
- return res <= hour;
145
+ return s <= hour;
183
146
}
184
147
}
185
148
```
@@ -190,25 +153,29 @@ class Solution {
190
153
class Solution {
191
154
public:
192
155
int minSpeedOnTime(vector<int >& dist, double hour) {
193
- int left = 1, right = 1e7;
194
- while (left < right) {
195
- int mid = (left + right) >> 1;
196
- if (check(dist, mid, hour)) {
197
- right = mid;
156
+ if (dist.size() > ceil(hour)) {
157
+ return -1;
158
+ }
159
+ const int m = 1e7;
160
+ int l = 1, r = m + 1;
161
+ int n = dist.size();
162
+ auto check = [ &] (int v) {
163
+ double s = 0;
164
+ for (int i = 0; i < n; ++i) {
165
+ double t = dist[ i] * 1.0 / v;
166
+ s += i == n - 1 ? t : ceil(t);
167
+ }
168
+ return s <= hour;
169
+ };
170
+ while (l < r) {
171
+ int mid = (l + r) >> 1;
172
+ if (check(mid)) {
173
+ r = mid;
198
174
} else {
199
- left = mid + 1;
175
+ l = mid + 1;
200
176
}
201
177
}
202
- return check(dist, left, hour) ? left : -1;
203
- }
204
-
205
- bool check(vector<int>& dist, int speed, double hour) {
206
- double res = 0;
207
- for (int i = 0; i < dist.size(); ++i) {
208
- double cost = dist[i] * 1.0 / speed;
209
- res += (i == dist.size() - 1 ? cost : ceil(cost));
210
- }
211
- return res <= hour;
178
+ return l > m ? -1 : l;
212
179
}
213
180
};
214
181
```
@@ -217,21 +184,58 @@ public:
217
184
218
185
```go
219
186
func minSpeedOnTime(dist []int, hour float64) int {
187
+ if float64(len(dist)) > math.Ceil(hour) {
188
+ return -1
189
+ }
190
+ const m int = 1e7
220
191
n := len(dist)
221
- const mx int = 1e7
222
- x := sort.Search (mx, func (s int ) bool {
223
- s++
224
- var cost float64
225
- for _ , v := range dist[:n-1 ] {
226
- cost += math.Ceil (float64 (v) / float64 (s))
192
+ ans := sort.Search(m+1, func(v int) bool {
193
+ v++
194
+ s := 0.0
195
+ for i, d := range dist {
196
+ t := float64(d) / float64(v)
197
+ if i == n-1 {
198
+ s += t
199
+ } else {
200
+ s += math.Ceil(t)
201
+ }
227
202
}
228
- cost += float64 (dist[n-1 ]) / float64 (s)
229
- return cost <= hour
230
- })
231
- if x == mx {
203
+ return s <= hour
204
+ }) + 1
205
+ if ans > m {
232
206
return -1
233
207
}
234
- return x + 1
208
+ return ans
209
+ }
210
+ ```
211
+
212
+ #### TypeScript
213
+
214
+ ``` ts
215
+ function minSpeedOnTime(dist : number [], hour : number ): number {
216
+ if (dist .length > Math .ceil (hour )) {
217
+ return - 1 ;
218
+ }
219
+ const n = dist .length ;
220
+ const m = 10 ** 7 ;
221
+ const check = (v : number ): boolean => {
222
+ let s = 0 ;
223
+ for (let i = 0 ; i < n ; ++ i ) {
224
+ const t = dist [i ] / v ;
225
+ s += i === n - 1 ? t : Math .ceil (t );
226
+ }
227
+ return s <= hour ;
228
+ };
229
+ let [l, r] = [1 , m + 1 ];
230
+ while (l < r ) {
231
+ const mid = (l + r ) >> 1 ;
232
+ if (check (mid )) {
233
+ r = mid ;
234
+ } else {
235
+ l = mid + 1 ;
236
+ }
237
+ }
238
+ return l > m ? - 1 : l ;
235
239
}
236
240
```
237
241
@@ -240,35 +244,33 @@ func minSpeedOnTime(dist []int, hour float64) int {
240
244
``` rust
241
245
impl Solution {
242
246
pub fn min_speed_on_time (dist : Vec <i32 >, hour : f64 ) -> i32 {
247
+ if dist . len () as f64 > hour . ceil () {
248
+ return - 1 ;
249
+ }
250
+ const M : i32 = 10_000_000 ;
251
+ let (mut l , mut r ) = (1 , M + 1 );
243
252
let n = dist . len ();
244
-
245
- let check = | speed | {
246
- let mut cur = 0.0 ;
247
- for (i , & d ) in dist . iter (). enumerate () {
248
- if i == n - 1 {
249
- cur += (d as f64 ) / (speed as f64 );
250
- } else {
251
- cur += ((d as f64 ) / (speed as f64 )). ceil ();
252
- }
253
+ let check = | v : i32 | -> bool {
254
+ let mut s = 0.0 ;
255
+ for i in 0 .. n {
256
+ let t = dist [i ] as f64 / v as f64 ;
257
+ s += if i == n - 1 { t } else { t . ceil () };
253
258
}
254
- cur <= hour
259
+ s <= hour
255
260
};
256
-
257
- let mut left = 1 ;
258
- let mut right = 1e 7 as i32 ;
259
- while left < right {
260
- let mid = left + (right - left ) / 2 ;
261
- if ! check (mid ) {
262
- left = mid + 1 ;
261
+ while l < r {
262
+ let mid = (l + r ) / 2 ;
263
+ if check (mid ) {
264
+ r = mid ;
263
265
} else {
264
- right = mid ;
266
+ l = mid + 1 ;
265
267
}
266
268
}
267
-
268
- if check (left ) {
269
- return left ;
269
+ if l > M {
270
+ - 1
271
+ } else {
272
+ l
270
273
}
271
- - 1
272
274
}
273
275
}
274
276
```
@@ -282,63 +284,30 @@ impl Solution {
282
284
* @return {number}
283
285
*/
284
286
var minSpeedOnTime = function (dist , hour ) {
285
- if (dist .length > Math .ceil (hour)) return - 1 ;
286
- let left = 1 ,
287
- right = 10 ** 7 ;
288
- while (left < right) {
289
- let mid = (left + right) >> 1 ;
290
- if (arriveOnTime (dist, mid, hour)) {
291
- right = mid;
292
- } else {
293
- left = mid + 1 ;
294
- }
295
- }
296
- return left;
297
- };
298
-
299
- function arriveOnTime (dist , speed , hour ) {
300
- let res = 0.0 ;
301
- let n = dist .length ;
302
- for (let i = 0 ; i < n; i++ ) {
303
- let cost = dist[i] / speed;
304
- if (i != n - 1 ) {
305
- cost = Math .ceil (cost);
306
- }
307
- res += cost;
287
+ if (dist .length > Math .ceil (hour)) {
288
+ return - 1 ;
308
289
}
309
- return res <= hour;
310
- }
311
- ```
312
-
313
- #### TypeScript
314
-
315
- ``` ts
316
- function minSpeedOnTime(dist : number [], hour : number ): number {
317
- if (dist .length > Math .ceil (hour )) return - 1 ;
318
-
319
- const check = (speed : number ) => {
320
- const n = dist .length ;
321
- let time = 0 ;
322
-
323
- for (let i = 0 ; i < n ; i ++ ) {
324
- const t = dist [i ] / speed ;
325
- time += i === n - 1 ? t : Math .ceil (t );
290
+ const n = dist .length ;
291
+ const m = 10 ** 7 ;
292
+ const check = v => {
293
+ let s = 0 ;
294
+ for (let i = 0 ; i < n; ++ i) {
295
+ const t = dist[i] / v;
296
+ s += i === n - 1 ? t : Math .ceil (t);
326
297
}
327
-
328
- return hour >= time ;
298
+ return s <= hour;
329
299
};
330
-
331
- const max = 10 ** 7 ;
332
- let [l, r] = [ 1 , max ] ;
333
-
334
- while ( l <= r ) {
335
- const i = ( l + r ) >> 1 ;
336
- if ( check ( i )) r = i - 1 ;
337
- else l = i + 1 ;
300
+ let [l, r] = [ 1 , m + 1 ];
301
+ while (l < r) {
302
+ const mid = (l + r) >> 1 ;
303
+ if ( check (mid)) {
304
+ r = mid;
305
+ } else {
306
+ l = mid + 1 ;
307
+ }
338
308
}
339
-
340
- return l <= max ? l : - 1 ;
341
- }
309
+ return l > m ? - 1 : l;
310
+ };
342
311
```
343
312
344
313
<!-- tabs: end -->
0 commit comments