Problem of The Day: Robot Collisions
Problem Statement
Intuition
Initially, I need to simulate the movement of the robots and handle the collisions based on their positions, healths, and directions. Robots moving towards each other will collide and the one with higher health will continue with reduced health, while the one with lower health will be removed.
Approach
- Initialize Robots: Create a list of robots with their positions, healths, directions, and original order.
- Sort by Positions: Sort the robots by their positions to handle collisions in order.
- Simulate Collisions: Use a stack to simulate the process of robots moving and colliding:
- Iterate through the list and push robots onto the stack.
- When a collision is detected (i.e., a right-moving robot meets a left-moving robot), compare their healths.
- The robot with higher health survives with its health decremented by one, and the other robot is removed.
- Check Stability: Repeat the process until no more collisions occur.
- Sort by Original Order: Once the final state is achieved, sort the robots by their original order to return the results in the correct sequence.
- Return Results: Return the healths of the surviving robots.
Complexity
- Time Complexity: The sorting step contributes \(O(n \log n)\), and the collision handling in the worst case can be \(O(n)\) for each pass. Since the number of passes depends on the collisions, in the worst case it can be \(O(n^2)\).
- Space Complexity: The space complexity is \(O(n)\) due to the additional space required to store robot information and the stack.
Code
class Solution:
def survivedRobotsHealths(self, positions: List[int], healths: List[int], directions: str) -> List[int]:
robots = []
n = len(positions)
# Initialize robots with positions, healths, directions, and original order
for i in range(n):
robot = {
'position': positions[i],
'health': healths[i],
'direction': -1 if directions[i] == 'L' else 1,
'order': i
}
robots.append(robot)
# Sort robots by their positions
robots.sort(key=lambda x: x['position'])
while True:
stack = []
while robots:
robot = robots.pop()
stack.append(robot)
# Handle collisions
while len(stack) >= 2 and stack[-1]['direction'] == 1 and stack[-2]['direction'] == -1:
robot_a = stack.pop()
robot_b = stack.pop()
if robot_a['health'] > robot_b['health']:
robot_a['health'] -= 1
stack.append(robot_a)
elif robot_a['health'] < robot_b['health']:
robot_b['health'] -= 1
stack.append(robot_b)
if not stack:
return []
# Prepare for next pass
robots = stack[:]
robots.sort(key=lambda x: x['position'])
l = 0
direction = robots[l]['direction']
while l < len(robots) and robots[l]['direction'] == direction:
l += 1
if l == len(robots):
break
if l >= 0 and robots[l - 1]['direction'] == -1 and robots[l]['direction'] == 1:
break
# Sort by original order and return the healths of surviving robots
robots.sort(key=lambda x: x['order'])
return [robot['health'] for robot in robots]
Editorial
Approach: Sorting & Stack
class Solution:
def survivedRobotsHealths(
self, positions: List[int], healths: List[int], directions: str
) -> List[int]:
n = len(positions)
indices = list(range(n))
result = []
stack = deque()
# Sort indices based on their positions
indices.sort(key=lambda x: positions[x])
for current_index in indices:
# Add right-moving robots to the stack
if directions[current_index] == "R":
stack.append(current_index)
else:
while stack and healths[current_index] > 0:
# Pop the top robot from the stack for collision check
top_index = stack.pop()
if healths[top_index] > healths[current_index]:
# Top robot survives, current robot is destroyed
healths[top_index] -= 1
healths[current_index] = 0
stack.append(top_index)
elif healths[top_index] < healths[current_index]:
# Current robot survives, top robot is destroyed
healths[current_index] -= 1
healths[top_index] = 0
else:
# Both robots are destroyed
healths[current_index] = 0
healths[top_index] = 0
# Collect surviving robots
for index in range(n):
if healths[index] > 0:
result.append(healths[index])
return result
- time: O(n log n)
- space: O(n)