Skip to content

Commit 5bb27b2

Browse files
authored
Update README.md
1 parent 61bf4e3 commit 5bb27b2

File tree

1 file changed

+137
-168
lines changed
  • solution/1800-1899/1870.Minimum Speed to Arrive on Time

1 file changed

+137
-168
lines changed

solution/1800-1899/1870.Minimum Speed to Arrive on Time/README.md

Lines changed: 137 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -83,60 +83,15 @@ tags:
8383

8484
### 方法一:二分查找
8585

86-
二分枚举速度值,找到满足条件的最小速度
86+
我们注意到,如果一个速度值 $v$ 能够使得我们在规定时间内到达,那么对于任意 $v' > v$,我们也一定能在规定时间内到达。这存在着单调性,因此我们可以使用二分查找,找到最小的满足条件的速度值
8787

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$
8989

90-
以下是二分查找的两个通用模板:
90+
问题转化为判断一个速度值 $v$ 是否能够在规定时间内到达。我们可以遍历每一趟列车,计算每一趟列车的运行时间 $t = \frac{d}{v}$,如果是最后一趟列车,我们直接加上 $t$,否则我们向上取整加上 $t$。最后判断总时间是否小于等于规定时间,如果是则说明满足条件。
9191

92-
模板 1:
92+
二分结束后,如果左边界超过了 $10^7$,说明无法在规定时间内到达,返回 $-1$,否则返回左边界。
9393

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)$。
14095

14196
<!-- tabs:start -->
14297

@@ -145,12 +100,15 @@ int search(int left, int right) {
145100
```python
146101
class Solution:
147102
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
150105
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
153109

110+
if len(dist) > ceil(hour):
111+
return -1
154112
r = 10**7 + 1
155113
ans = bisect_left(range(1, r), True, key=check) + 1
156114
return -1 if ans == r else ans
@@ -161,25 +119,30 @@ class Solution:
161119
```java
162120
class Solution {
163121
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;
167129
if (check(dist, mid, hour)) {
168-
right = mid;
130+
r = mid;
169131
} else {
170-
left = mid + 1;
132+
l = mid + 1;
171133
}
172134
}
173-
return check(dist, left, hour) ? left : -1;
135+
return l > m ? -1 : l;
174136
}
175137

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);
181144
}
182-
return res <= hour;
145+
return s <= hour;
183146
}
184147
}
185148
```
@@ -190,25 +153,29 @@ class Solution {
190153
class Solution {
191154
public:
192155
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;
198174
} else {
199-
left = mid + 1;
175+
l = mid + 1;
200176
}
201177
}
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;
212179
}
213180
};
214181
```
@@ -217,21 +184,58 @@ public:
217184
218185
```go
219186
func minSpeedOnTime(dist []int, hour float64) int {
187+
if float64(len(dist)) > math.Ceil(hour) {
188+
return -1
189+
}
190+
const m int = 1e7
220191
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+
}
227202
}
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 {
232206
return -1
233207
}
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;
235239
}
236240
```
237241

@@ -240,35 +244,33 @@ func minSpeedOnTime(dist []int, hour float64) int {
240244
```rust
241245
impl Solution {
242246
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);
243252
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() };
253258
}
254-
cur <= hour
259+
s <= hour
255260
};
256-
257-
let mut left = 1;
258-
let mut right = 1e7 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;
263265
} else {
264-
right = mid;
266+
l = mid + 1;
265267
}
266268
}
267-
268-
if check(left) {
269-
return left;
269+
if l > M {
270+
-1
271+
} else {
272+
l
270273
}
271-
-1
272274
}
273275
}
274276
```
@@ -282,63 +284,30 @@ impl Solution {
282284
* @return {number}
283285
*/
284286
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;
308289
}
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);
326297
}
327-
328-
return hour >= time;
298+
return s <= hour;
329299
};
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+
}
338308
}
339-
340-
return l <= max ? l : -1;
341-
}
309+
return l > m ? -1 : l;
310+
};
342311
```
343312

344313
<!-- tabs:end -->

0 commit comments

Comments
 (0)