Decide Whether a Vehicle Is Ready from Maintenance Open and End Events
Company: Waymo
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
A vehicle's maintenance log is a list of events. Each event either opens or ends a maintenance task of one type, such as `oil` or `brake`. The vehicle is ready to go only if every task that was opened has also been ended, and no type ever had two tasks open at the same time. Write a function that decides whether the vehicle is ready to go.
### Function Signature
```python
def is_ready_to_go(events: list[list[str]]) -> bool:
```
### Rules
- `events[i] = [action, time, type]`, where `action` is `"open"` or `"end"`, `time` is a non-negative integer written as a decimal string, and `type` names the maintenance task.
- The events are not necessarily listed in time order. Process them in increasing order of `time`, comparing times as integers (`"9"` comes before `"10"`). Events with equal times are processed in the order in which they appear in `events`.
- Processing `"open"` for a type that already has an open task is a violation: each type can have at most one open task at a time. Different types can be open at the same time.
- Processing `"end"` for a type closes that type's open task. If the type has no open task, it is a violation.
- Return `True` if no violation occurs and no task is still open after the last event; otherwise return `False`. An empty list returns `True`.
- Because of the tie rule, `[["open", "4", "oil"], ["end", "4", "oil"]]` returns `True`, while `[["end", "4", "oil"], ["open", "4", "oil"]]` returns `False`.
### Constraints
- `0 <= len(events) <= 10^5`
- `action` is exactly `"open"` or `"end"`.
- `time` is the decimal form of an integer `0 <= time <= 10^9`, with no leading zeros (`"0"` itself is allowed), so every parsed time fits in a 32-bit signed integer.
- `type` has 1 to 20 characters, each a lowercase English letter or an underscore. Types are compared exactly.
### Examples
**Example 1**
```text
Input: events = [["end", "6", "brake"], ["open", "1", "oil"], ["open", "2", "brake"],
["end", "4", "oil"], ["open", "4", "oil"], ["end", "9", "oil"]]
Output: True
```
In time order: `oil` opens at 1, `brake` opens at 2, `oil` ends at 4 and opens again at 4 (the end comes first in the input), `brake` ends at 6, and `oil` ends at 9. No type overlaps itself and nothing is left open.
**Example 2**
```text
Input: events = [["open", "1", "oil"], ["open", "3", "oil"], ["end", "5", "oil"], ["end", "7", "oil"]]
Output: False
```
At time 3 an `oil` task opens while the one opened at time 1 is still open.
**Example 3**
```text
Input: events = [["open", "2", "tire"], ["end", "8", "tire"], ["open", "5", "brake"]]
Output: False
```
The `tire` task is opened and ended, but the `brake` task opened at time 5 is never ended.
Overview: Given vehicle maintenance events of the form open or end, time and type, decide whether the vehicle is ready to go: every opened task must be ended and no type may have two tasks open at once. It tests event ordering with ties, per-type state tracking, and careful validation of unmatched events.
Read the full Waymo Software Engineer interview experience this question came from
A vehicle's maintenance log is a list of events. Each event either opens or ends a maintenance task of one type, such as `oil` or `brake`. The vehicle is ready to go only if every task that was opened has also been ended, and no type ever had two tasks open at the same time.
Implement `is_ready_to_go(events)`, which returns whether the vehicle is ready to go (`True`/`False` in Python, `true`/`false` in JavaScript, Java and C++).
### Rules
- `events[i] = [action, time, type]`, where `action` is `"open"` or `"end"`, `time` is a non-negative integer written as a decimal string, and `type` names the maintenance task.
- The events are not necessarily listed in time order. Process them in increasing order of `time`, comparing times as integers (`"9"` comes before `"10"`). Events with equal times are processed in the order in which they appear in `events`.
- Processing `"open"` for a type that already has an open task is a violation: each type can have at most one open task at a time. Different types can be open at the same time.
- Processing `"end"` for a type closes that type's open task. If the type has no open task, it is a violation.
- Return `True` if no violation occurs and no task is still open after the last event; otherwise return `False`. An empty list returns `True`.
- Because of the tie rule, `[["open", "4", "oil"], ["end", "4", "oil"]]` returns `True`, while `[["end", "4", "oil"], ["open", "4", "oil"]]` returns `False`.
### Constraints
- `0 <= len(events) <= 10^5`
- Each `events[i]` is a list of exactly three strings `[action, time, type]`.
- `action` is exactly `"open"` or `"end"`.
- `time` is the decimal form of an integer `0 <= time <= 10^9`, with no leading zeros (`"0"` itself is allowed), so every parsed time fits in a 32-bit signed integer; no value in this problem exceeds 2^31 - 1.
- `type` has 1 to 20 characters, each a lowercase English letter or an underscore. Types are compared exactly.
### Example 1
```text
Input: events = [["end", "6", "brake"], ["open", "1", "oil"], ["open", "2", "brake"],
["end", "4", "oil"], ["open", "4", "oil"], ["end", "9", "oil"]]
Output: True
```
In time order: `oil` opens at 1, `brake` opens at 2, `oil` ends at 4 and opens again at 4 (the end comes first in the input), `brake` ends at 6, and `oil` ends at 9. No type overlaps itself and nothing is left open.
### Example 2
```text
Input: events = [["open", "1", "oil"], ["open", "3", "oil"], ["end", "5", "oil"], ["end", "7", "oil"]]
Output: False
```
At time 3 an `oil` task opens while the one opened at time 1 is still open.
Constraints
- 0 <= len(events) <= 10^5
- Each events[i] is a list of exactly three strings [action, time, type].
- action is exactly "open" or "end".
- time is the decimal form of an integer 0 <= time <= 10^9, with no leading zeros ("0" itself is allowed), so every parsed time fits in a 32-bit signed integer.
- type has 1 to 20 characters, each a lowercase English letter or an underscore. Types are compared exactly.
Examples
Input: ([],)
Expected Output: True
Explanation: Empty log: no violation and nothing is open, so the vehicle is ready.
Input: ([['open', '5', 'oil']],)
Expected Output: False
Explanation: Single open event: the oil task is still open after the last event.
Hints
- The order of the input list is not the order in which events take effect. Work out exactly which order the rules require, including what happens when two events share a time.
- Times are given as strings, but "9" must come before "10": compare their integer values, not their text.
- Each type can have at most one open task, so at any moment a type is either open or not open.