2211. Count Collisions on a Road
Problem Description
You have n
cars positioned on an infinitely long road, numbered from 0
to n - 1
from left to right. Each car occupies a unique position on the road.
You're given a string directions
of length n
where each character represents a car's movement:
'L'
means the car is moving left'R'
means the car is moving right'S'
means the car is stationary (not moving)
All moving cars travel at the same speed.
When cars collide, the collision count increases based on these rules:
- When two cars moving in opposite directions collide (one going left, one going right), the collision count increases by
2
- When a moving car collides with a stationary car, the collision count increases by
1
After any collision, the cars involved stop moving and remain at the collision point. Cars cannot change their direction or state except when colliding.
Your task is to calculate the total number of collisions that will occur.
The key insight is that cars moving left at the beginning ('L'
) will never collide with anything since there's nothing to their left. Similarly, cars moving right at the end ('R'
) will never collide since there's nothing to their right. Therefore, we can ignore the prefix of 'L'
characters and suffix of 'R'
characters.
For the remaining middle portion, any car that isn't stationary ('S'
) will eventually collide and contribute to the collision count. Each non-'S'
character in this middle portion contributes exactly 1
to the total collision count, as each represents one car that will stop due to a collision.
The solution strips the irrelevant prefix 'L'
and suffix 'R'
, then counts all non-'S'
characters in the remaining string, which equals the total length minus the count of 'S'
characters.
Intuition
Let's think about what happens to each car step by step.
First, consider the cars at the boundaries. Cars moving left at the leftmost positions will just keep going left forever without hitting anything. Similarly, cars moving right at the rightmost positions will keep going right forever. These cars will never contribute to any collisions.
Now, what about the cars in between? Let's trace through what happens:
- If a car is moving right (
'R'
) and encounters a stationary car ('S'
) or a car moving left ('L'
), it will collide and stop. - If a car is moving left (
'L'
) and encounters a stationary car ('S'
) or a car moving right ('R'
), it will collide and stop. - Once any collision happens, the colliding cars become stationary, creating a "wall" that other moving cars will eventually hit.
The key realization is that once we remove the cars that escape (prefix 'L'
and suffix 'R'
), every remaining moving car MUST eventually collide with something. Why? Because:
- A car moving right will either hit another car directly or hit a "wall" of stopped cars
- A car moving left will either hit another car directly or hit a "wall" of stopped cars
- The collision creates a chain reaction where stopped cars act as barriers for other moving cars
Each moving car that collides contributes exactly 1
to our answer when it stops. It doesn't matter if two cars collide head-on (contributing 2
total) or if one car hits a stationary car (contributing 1
) - in both cases, each moving car that stops adds exactly 1
to our count.
Therefore, the answer is simply the count of all moving cars that will eventually stop, which is all the 'L'
and 'R'
characters in the middle section (after removing the escaping prefix and suffix). This equals len(middle_section) - count('S')
.
Learn more about Stack patterns.
Solution Approach
The implementation is remarkably elegant once we understand the intuition. Here's how we translate our understanding into code:
Step 1: Remove cars that will never collide
We use Python's string methods to strip away the cars that escape:
lstrip("L")
removes all consecutive'L'
characters from the beginning of the stringrstrip("R")
removes all consecutive'R'
characters from the end of the string
For example, if directions = "LLRRLSSRL"
:
- After
lstrip("L")
:"RRLSSRL"
- After
rstrip("R")
:"RRLSSR"
This gives us s = directions.lstrip("L").rstrip("R")
, which contains only the cars that might participate in collisions.
Step 2: Count the moving cars that will collide
In the remaining string s
, every car that isn't stationary will eventually collide and stop. We need to count:
- All
'L'
characters (cars moving left that will hit something) - All
'R'
characters (cars moving right that will hit something)
This is equivalent to counting all non-'S'
characters in s
.
The count can be calculated as:
total_cars - stationary_cars = len(s) - s.count("S")
Complete Solution:
class Solution:
def countCollisions(self, directions: str) -> int:
s = directions.lstrip("L").rstrip("R")
return len(s) - s.count("S")
Time Complexity: O(n)
where n
is the length of the directions string. We traverse the string a constant number of times for the strip operations and counting.
Space Complexity: O(1)
as we only use a constant amount of extra space (the stripped string reuses the original string's memory in Python).
The beauty of this solution lies in recognizing that we don't need to simulate the actual collisions - we just need to identify which cars will eventually stop, turning a potentially complex simulation problem into a simple counting problem.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through a concrete example to see how the solution works.
Example: directions = "LLRSSRL"
Step 1: Identify cars that will never collide
First, let's visualize the initial setup with 7 cars (indexed 0-6):
Position: 0 1 2 3 4 5 6 Car: L L R S S R L Motion: ← ← → - - → ←
The leftmost cars (positions 0 and 1) are moving left (L
). Since there's nothing to their left, they'll escape forever without hitting anything.
The rightmost car (position 6) is moving left (L
), so it might collide with something to its left.
Step 2: Strip the escaping cars
- Remove prefix
L
s:"LLRSSRL"
→"RSSRL"
- Remove suffix
R
s:"RSSRL"
→"RSSRL"
(no trailingR
s to remove)
So our trimmed string is s = "RSSRL"
Step 3: Count collisions
In the trimmed string "RSSRL"
, we have:
- Position 0:
R
(moving right) - will eventually hit the stationary car at position 1 - Position 1:
S
(stationary) - already stopped, won't contribute - Position 2:
S
(stationary) - already stopped, won't contribute - Position 3:
R
(moving right) - will eventually hit the car moving left at position 4 - Position 4:
L
(moving left) - will collide head-on with the car at position 3
Every moving car (R
or L
) in this trimmed section will eventually stop due to a collision:
- The first
R
hits the stationary carS
→ contributes 1 - The second
R
and theL
collide head-on → each contributes 1 (total 2)
Total moving cars that will collide = Total cars - Stationary cars
= len("RSSRL") - count('S')
= 5 - 2
= 3
Therefore, the answer is 3.
Solution Implementation
1class Solution:
2 def countCollisions(self, directions: str) -> int:
3 # Remove cars moving left from the start (they won't collide)
4 trimmed_left = directions.lstrip("L")
5
6 # Remove cars moving right from the end (they won't collide)
7 trimmed_both = trimmed_left.rstrip("R")
8
9 # Count collisions: all remaining non-stationary cars will collide
10 # Total cars in middle region minus already stationary cars
11 total_cars_in_middle = len(trimmed_both)
12 stationary_cars = trimmed_both.count("S")
13 collisions = total_cars_in_middle - stationary_cars
14
15 return collisions
16```
17
18Or in the more concise form matching the original style:
19
20```python3
21class Solution:
22 def countCollisions(self, directions: str) -> int:
23 # Remove non-colliding cars: left-moving cars at start and right-moving cars at end
24 s = directions.lstrip("L").rstrip("R")
25
26 # Count collisions: all remaining moving cars (non-'S') will eventually collide
27 return len(s) - s.count("S")
28
1class Solution {
2 public int countCollisions(String directions) {
3 // Convert string to char array for easier manipulation
4 char[] directionArray = directions.toCharArray();
5 int length = directionArray.length;
6
7 // Find the leftmost non-'L' car
8 // Cars moving left at the beginning won't collide with anything
9 int leftBoundary = 0;
10 while (leftBoundary < length && directionArray[leftBoundary] == 'L') {
11 leftBoundary++;
12 }
13
14 // Find the rightmost non-'R' car
15 // Cars moving right at the end won't collide with anything
16 int rightBoundary = length - 1;
17 while (rightBoundary >= 0 && directionArray[rightBoundary] == 'R') {
18 rightBoundary--;
19 }
20
21 // Calculate total collisions
22 // All cars between boundaries will eventually stop (collision count = 2 per moving car)
23 // This counts all cars in the collision zone
24 int totalCollisions = rightBoundary - leftBoundary + 1;
25
26 // Subtract stationary cars as they don't contribute to collision count
27 // Stationary cars ('S') are already stopped and won't generate collisions
28 for (int i = leftBoundary; i <= rightBoundary; i++) {
29 if (directionArray[i] == 'S') {
30 totalCollisions--;
31 }
32 }
33
34 return totalCollisions;
35 }
36}
37
1class Solution {
2public:
3 int countCollisions(string s) {
4 int n = s.size();
5
6 // Find the leftmost position where cars are not moving left
7 // Cars moving left at the beginning won't collide with anything
8 int leftBoundary = 0;
9 while (leftBoundary < n && s[leftBoundary] == 'L') {
10 ++leftBoundary;
11 }
12
13 // Find the rightmost position where cars are not moving right
14 // Cars moving right at the end won't collide with anything
15 int rightBoundary = n - 1;
16 while (rightBoundary >= 0 && s[rightBoundary] == 'R') {
17 --rightBoundary;
18 }
19
20 // Count total collisions:
21 // All cars between leftBoundary and rightBoundary (inclusive) will eventually stop
22 // except those already stationary ('S')
23 // Total cars in range - stationary cars = cars that will collide
24 int totalCarsInRange = rightBoundary - leftBoundary + 1;
25 int stationaryCars = count(s.begin() + leftBoundary,
26 s.begin() + rightBoundary + 1, 'S');
27
28 return totalCarsInRange - stationaryCars;
29 }
30};
31
1/**
2 * Counts the number of collisions that will occur when cars move according to their directions.
3 * Cars moving left ('L') or right ('R') will collide and stop ('S').
4 *
5 * @param directions - A string where each character represents a car's direction ('L', 'R', or 'S')
6 * @returns The total number of collisions
7 */
8function countCollisions(directions: string): number {
9 const length: number = directions.length;
10
11 // Find the leftmost car that isn't moving left (will cause collisions)
12 let leftBoundary: number = 0;
13 while (leftBoundary < length && directions[leftBoundary] === 'L') {
14 leftBoundary++;
15 }
16
17 // Find the rightmost car that isn't moving right (will cause collisions)
18 let rightBoundary: number = length - 1;
19 while (rightBoundary >= 0 && directions[rightBoundary] === 'R') {
20 rightBoundary--;
21 }
22
23 // Count all cars between boundaries (they will all eventually stop due to collisions)
24 let collisionCount: number = rightBoundary - leftBoundary + 1;
25
26 // Subtract cars that are already stopped (they don't contribute to new collisions)
27 for (let i: number = leftBoundary; i <= rightBoundary; i++) {
28 if (directions[i] === 'S') {
29 collisionCount--;
30 }
31 }
32
33 return collisionCount;
34}
35
Time and Space Complexity
Time Complexity: O(n)
, where n
is the length of the string directions
.
The time complexity breaks down as follows:
lstrip("L")
:O(n)
in the worst case when all characters are "L"rstrip("R")
:O(n)
in the worst case when all remaining characters are "R"len(s)
:O(1)
operations.count("S")
:O(n)
as it needs to traverse the entire strings
Since these operations are performed sequentially, the overall time complexity is O(n) + O(n) + O(1) + O(n) = O(n)
.
Space Complexity: O(n)
or O(1)
, depending on the Python implementation.
The space complexity analysis:
- In Python, strings are immutable, so
lstrip()
andrstrip()
create new string objects. This results inO(n)
space complexity as a new strings
is created. - However, if we consider only the additional space used by the algorithm (not counting the space for the output), the space complexity could be considered
O(1)
since no additional data structures proportional to the input size are used beyond the string manipulation.
The reference answer mentions both O(n)
and O(1)
because it depends on whether we count the space used for creating the intermediate string s
or only the auxiliary space used by the algorithm.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Misunderstanding the Collision Count Rules
The Mistake: A common error is thinking that each collision between two moving cars contributes 1 to the count, not 2. This leads to incorrect calculations where developers might try to count pairs of colliding cars differently.
Why It Happens: The problem states that when two cars moving in opposite directions collide, the count increases by 2. Some might interpret this as "one collision = 1 count" and miss the special case.
The Reality: The solution works because it counts each car that stops, not each collision event. When two moving cars collide (R meets L), both cars stop, contributing 2 to the count (1 for each car). When a moving car hits a stationary one, only the moving car stops, contributing 1.
Example:
"RL"
→ Both cars stop → Count = 2"RS"
→ Only R stops → Count = 1"SL"
→ Only L stops → Count = 1
Pitfall 2: Attempting to Simulate Actual Collisions
The Mistake: Trying to track car positions and simulate movement step-by-step, checking for collisions at each time unit.
Why It Happens: The problem description naturally suggests a simulation approach, making it tempting to model cars moving along the road.
The Fix: Recognize that the final count only depends on which cars will eventually stop, not when or where they collide. Every non-stationary car in the "collision zone" (after removing escaping cars) will eventually stop.
Pitfall 3: Incorrectly Handling Edge Cases
The Mistake: Forgetting to handle strings that become empty after stripping, or strings containing only 'S' characters.
Example Cases:
"LLL"
→ After stripping:""
→ Count should be 0"RRR"
→ After stripping:""
→ Count should be 0"SSS"
→ After stripping:"SSS"
→ Count should be 0
The Solution: The given code naturally handles these cases:
- Empty string after stripping:
len("") - "".count("S") = 0 - 0 = 0
- Only stationary cars:
len("SSS") - "SSS".count("S") = 3 - 3 = 0
Pitfall 4: Order of Stripping Operations
The Mistake: Applying rstrip("R")
before lstrip("L")
or trying to strip both simultaneously.
Why It Matters: While the order doesn't affect the final result for this problem, understanding the logic flow is important. We remove left-escaping cars first, then right-escaping cars from what remains.
Correct Approach:
# Correct: left first, then right s = directions.lstrip("L").rstrip("R") # Also correct but less intuitive: s = directions.rstrip("R").lstrip("L") # Incorrect attempt at simultaneous stripping: # s = directions.strip("LR") # This would remove L and R from both ends!
The strip("LR")
would incorrectly remove any combination of 'L' and 'R' from both ends, which is not what we want.
Which of the following uses divide and conquer strategy?
Recommended Readings
Stack Intro Imagine you have a pile of books on your desk If you want to add a new book you place it on top If you want to read a book you take it from the top And if you simply want to see which book is on the top you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!