Problem: Robot Collisions

There are `n` 1-indexed robots, each having a position on a line, health, and
movement direction.

You are given 0-indexed integer arrays `positions`, `healths`, and a string
`directions` (`directions[i]` is either 'L' for left or 'R' for right). All
integers in `positions` are unique.

All robots start moving on the line simultaneously at the same speed in their
given directions. If two robots ever share the same position while moving,
they will collide.

If two robots collide, the robot with lower health is removed from the line,
and the health of the other robot decreases by one. The surviving robot
continues in the same direction it was going. If both robots have the same
health, they are both removed from the line.

Your task is to determine the health of the robots that survive the
collisions, in the same order that the robots were given, i.e. final heath of
robot 1 (if survived), final health of robot 2 (if survived), and so on. If
there are no survivors, return an empty array.

Return an array containing the health of the remaining robots (in the order
they were given in the input), after no further collisions can occur.

Note: The positions may be unsorted.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator
from dataclasses import dataclass

@dataclass
class Robot:
  index: int
  position: int
  health: int
  direction: str


class Solution:
  def survivedRobotsHealths(self, positions: List[int], healths: List[int], directions: str) -> List[int]:
    robots = sorted([Robot(index, position, health, direction) for index, (position, health, direction) in enumerate(zip(positions, healths, directions))], key=lambda robot: robot.position)
    stack: List[Robot] = []

    for robot in robots:
      if robot.direction == 'R':
        stack.append(robot)
        continue
      while stack and stack[-1].direction == 'R' and robot.health > 0:
        if stack[-1].health == robot.health:
          stack.pop()
          robot.health = 0
        elif stack[-1].health < robot.health:
          stack.pop()
          robot.health -= 1
        else:
          stack[-1].health -= 1
          robot.health = 0
      if robot.health > 0:
        stack.append(robot)

    stack.sort(key=lambda robot: robot.index)
    return [robot.health for robot in stack]


Java solution:
class Robot {
  public int index;
  public int position;
  public int health;
  public char direction;
  public Robot(int index, int position, int health, char direction) {
    this.index = index;
    this.position = position;
    this.health = health;
    this.direction = direction;
  }
}

class Solution {
  public List<Integer> survivedRobotsHealths(int[] positions, int[] healths, String directions) {
    List<Integer> ans = new ArrayList<>();
    Robot[] robots = new Robot[positions.length];
    List<Robot> stack = new ArrayList<>(); // running robots

    for (int i = 0; i < positions.length; ++i)
      robots[i] = new Robot(i, positions[i], healths[i], directions.charAt(i));

    Arrays.sort(robots, Comparator.comparingInt((Robot robot) -> robot.position));

    for (Robot robot : robots) {
      if (robot.direction == 'R') {
        stack.add(robot);
        continue;
      }
      // Collide with robots going right if any.
      while (!stack.isEmpty() && stack.get(stack.size() - 1).direction == 'R' && robot.health > 0) {
        if (stack.get(stack.size() - 1).health == robot.health) {
          stack.remove(stack.size() - 1);
          robot.health = 0;
        } else if (stack.get(stack.size() - 1).health < robot.health) {
          stack.remove(stack.size() - 1);
          robot.health -= 1;
        } else { // stack[-1].health > robot.health
          stack.get(stack.size() - 1).health -= 1;
          robot.health = 0;
        }
      }
      if (robot.health > 0)
        stack.add(robot);
    }

    stack.sort(Comparator.comparingInt((Robot robot) -> robot.index));

    for (Robot robot : stack)
      ans.add(robot.health);

    return ans;
  }
}


C++ solution:
struct Robot {
  int index;
  int position;
  int health;
  char direction;
};

class Solution {
 public:
  vector<int> survivedRobotsHealths(vector<int>& positions,
                                    vector<int>& healths, string directions) {
    vector<int> ans;
    vector<Robot> robots;
    vector<Robot> stack;  // the runnnig robots

    for (int i = 0; i < positions.size(); ++i)
      robots.push_back(Robot{i, positions[i], healths[i], directions[i]});

    ranges::sort(robots, ranges::less{},
                 [](const Robot& robot) { return robot.position; });

    for (Robot& robot : robots) {
      if (robot.direction == 'R') {
        stack.push_back(robot);
        continue;
      }
      // Collide with robots going right if any.
      while (!stack.empty() && stack.back().direction == 'R' &&
             robot.health > 0) {
        if (stack.back().health == robot.health) {
          stack.pop_back();
          robot.health = 0;
        } else if (stack.back().health < robot.health) {
          stack.pop_back();
          robot.health -= 1;
        } else {  // stack.back().health > robot.health
          stack.back().health -= 1;
          robot.health = 0;
        }
      }
      if (robot.health > 0)
        stack.push_back(robot);
    }

    ranges::sort(stack, ranges::less{},
                 [](const Robot& robot) { return robot.index; });

    for (const Robot& robot : stack)
      ans.push_back(robot.health);

    return ans;
  }
};