着く 時刻を 前から 比べて 一本道で ゴールに 着く 自転車の 群れを数える
追い
海外で定番の問題リスト 4 本には入っていません
問題
追いtarget メートルのposition[i] メートルのspeed[i] メートルで
速い
- ちょうど
ゴールの 地点で 追いついた ときも、 同じ 群れとして数えます positionとspeedの長さは 同じで、 1 以上 100000 以下です position[i]は 0 以上target未満で、同じ 位置の 自転車は いません。 targetは 1 以上 1000000 以下ですspeed[i]は 1 以上 1000000 以下です
入力と出力の例
例 1
ゴールに
例 2
1 台だけでも 1 つの
例 3
どちらも 5 秒で
面接での聞かれ方
面接では、
- 「同じ
道を 走る 車が、 目的地に いくつの 集団で 着くかを 数えてください」 - 「ちょうど
目的地で 追いついたら、 同じ 集団ですか?」と、 境目を 自分から 確かめるかを 見られます - 書き終えた
あとに 「着く 時刻を 小数で 比べて 大丈夫ですか?」と 聞かれる こともあります
追いつく
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「スタックとキュー」に、
関わる学び
スタックは
まず 考える手順
段 1
自転車ごとに、
段 2
ゴールに
段 3
この
段 4
時刻は
解答
Python
Python
def count_fleets(
target, position, speed
):
cars = sorted(
zip(position, speed),
reverse=True,
)
fleets = 0
fd, fs = 0, 1
for p, s in cars:
d = target - p
if d * fs > fd * s:
fleets += 1
fd, fs = d, s
return fleetsJavaScript
JavaScript
function countFleets(
target,
position,
speed
) {
const cars = position.map(
(p, i) => [p, speed[i]]
);
cars.sort(
(a, b) => b[0] - a[0]
);
let fleets = 0;
let fd = 0;
let fs = 1;
for (const [p, s] of cars) {
const d = target - p;
if (d * fs > fd * s) {
fleets++;
fd = d;
fs = s;
}
}
return fleets;
}Go
Go
import "sort"
func countFleets(
target int,
position []int,
speed []int,
) int {
n := len(position)
idx := make([]int, n)
for i := range idx {
idx[i] = i
}
sort.Slice(idx, func(
a, b int,
) bool {
return position[idx[a]] >
position[idx[b]]
})
fleets := 0
fd, fs := 0, 1
for _, i := range idx {
d := target - position[i]
s := speed[i]
if d*fs > fd*s {
fleets++
fd, fs = d, s
}
}
return fleets
}自転車をfd と fs は、fd ÷ fs で、d ÷ s がd * fs > fd * s でfd を 0、fs を 1 に
計算量
- 時間は O(n log n) です。
並べ替えが いちばん重く、 その あとは 1 回なめるだけです - 使う
記憶は O(n) です。 並べ替えた 組か 添字の 並びを持ちます - 自転車の
組ごとに 追いつくかを 調べる 書き方は、 組の 数だけ 見るので O(n²) です
よく ある間違い
- 入力の
順のまま見る。 入力は ゴールに 近い順とは 限りません。 例 1 の positionもばらばらです。先に 位置で 並べ替えます - 前の
自転車 1 台とだけ比べる。 比べる 相手は、 前の 群れの 着く 時刻です。 追いついた 自転車のもとの 時刻と 比べると、 その 自転車よりは 遅くても 前の 群れには 追いつく 後ろの 自転車を、 新しい 群れと 数え 違えます。 たとえば 6 秒の 群れに 3 秒の 自転車が 追いついた あと、 4 秒の 自転車は 3 秒より 遅くても 6 秒の 群れに 追いつきます - 同じ
時刻を 別の 群れにする。 例 3 のように、 ちょうど ゴールで 追いつくのは 同じ 群れです。 新しい 群れに なるのは、 時刻が 真に 大きい ときだけです - 時刻を
小数の 割り算で比べる。 多くの 場合は 合いますが、 ちょうど 同じ 時刻の ときに 誤差で 食い 違う おそれが あります。 掛け算に 直して 整数で比べます
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「追い
越しが できないので、 後ろの 自転車は 前の 群れより 先に 着けません。 ゴールに 近い順に 並べ替え、 ほかが いない ときに 着く 時刻を 出します。 前の 群れの 時刻以下なら 追いついて 同じ 群れ、 より 大きければ 新しい 群れです。 時刻は 割り算を 避けて、 掛け算の 整数で 比べます。 並べ替えで O(n log n) です。」
書き終えたら、
「例 1 で
たどります。 近い順に 14、 8、 6、 2 です。 14 は 6 秒で 1 つ目の 群れ。 8 は 3 秒で 6 秒以下なので 追いつきます。 6 は 14 秒で 6 秒より 遅いので 2 つ目の 群れ。 2 は 6 秒で 14 秒以下なので 追いつきます。 答えは 2 です。」