package car_fleet import ( "math" "slices" ) type Car struct { Position float64 Speed float64 } // The TIME at which the two cars will collide with each other. func (c Car) CollidesInto(o Car) float64 { if c.Speed == o.Speed { return math.Inf(1) } return float64(c.Position-o.Position) / float64(o.Speed-c.Speed) } // The DISTANCE the car will be at a point in time. func (c Car) At(time float64) float64 { return c.Position + c.Speed*time } // The TIME the car will reach a certain distance. func (c Car) Reaches(target float64) float64 { if c.Speed == 0 { return math.Inf(1) } return (target - c.Position) / c.Speed } type Interval struct { From float64 To float64 } func (i Interval) Contains(point float64) bool { return point >= i.From && point <= i.To } func (i Interval) Intersect(o Interval) Interval { return Interval{ From: max(i.From, o.From), To: min(i.To, o.To), } } type Trajectory struct { Car Interval } func sortByInversePosition(a Car, b Car) int { return int(b.Position - a.Position) } func CarFleet(target int, position []int, speed []int) int { cars := []Car{} ends := map[float64]bool{} for i := range position { cars = append(cars, Car{ Position: float64(position[i]), Speed: float64(speed[i]), }) } slices.SortFunc(cars, sortByInversePosition) stack := []Trajectory{} for _, car := range cars { fastest_trajectory := Trajectory{ Car: car, Interval: Interval{ From: 0, To: car.Reaches(float64(target)), }, } for { if len(stack) == 0 { stack = append(stack, fastest_trajectory) break } first_trajectory := stack[len(stack)-1] collision_time := car.CollidesInto(first_trajectory.Car) if fastest_trajectory.Intersect(first_trajectory.Interval).Contains(collision_time) { first_trajectory.From = collision_time fastest_trajectory.To = collision_time stack = append(stack, fastest_trajectory) break } stack = stack[:len(stack)-1] } ends[stack[0].To] = true } return len(ends) }