leetcode
leetcode 2351 ~ 2400
机器人碰撞

机器人碰撞

难度:

标签:

题目描述

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.

 

 

Example 1:

Input: positions = [5,4,3,2,1], healths = [2,17,9,15,10], directions = "RRRRR"
Output: [2,17,9,15,10]
Explanation: No collision occurs in this example, since all robots are moving in the same direction. So, the health of the robots in order from the first robot is returned, [2, 17, 9, 15, 10].

Example 2:

Input: positions = [3,5,2,6], healths = [10,10,15,12], directions = "RLRL"
Output: [14]
Explanation: There are 2 collisions in this example. Firstly, robot 1 and robot 2 will collide, and since both have the same health, they will be removed from the line. Next, robot 3 and robot 4 will collide and since robot 4's health is smaller, it gets removed, and robot 3's health becomes 15 - 1 = 14. Only robot 3 remains, so we return [14].

Example 3:

Input: positions = [1,2,5,6], healths = [10,10,11,11], directions = "RLRL"
Output: []
Explanation: Robot 1 and robot 2 will collide and since both have the same health, they are both removed. Robot 3 and 4 will collide and since both have the same health, they are both removed. So, we return an empty array, [].

 

Constraints:

  • 1 <= positions.length == healths.length == directions.length == n <= 105
  • 1 <= positions[i], healths[i] <= 109
  • directions[i] == 'L' or directions[i] == 'R'
  • All values in positions are distinct

代码结果

运行时间: 169 ms, 内存: 31.5 MB


/*
 * 思路:
 * 1. 将机器人按位置排序。
 * 2. 使用栈来模拟机器人碰撞的过程。
 * 3. 遍历机器人,如果当前方向为'R',将其入栈。
 * 4. 如果当前方向为'L',则判断栈顶机器人方向是否为'R',是则发生碰撞,根据健康度决定结果。
 * 5. 最后输出幸存机器人的健康度。
 */

import java.util.*;
import java.util.stream.*;

public class RobotSurvivorStream {
    public int[] surviveRobots(int[] positions, int[] healths, String directions) {
        int n = positions.length;
        List<Robot> robots = IntStream.range(0, n)
                .mapToObj(i -> new Robot(positions[i], healths[i], directions.charAt(i)))
                .sorted(Comparator.comparingInt(r -> r.position))
                .collect(Collectors.toList());
        Deque<Robot> stack = new ArrayDeque<>();
        robots.forEach(robot -> {
            if (robot.direction == 'R') {
                stack.push(robot);
            } else {
                while (!stack.isEmpty() && stack.peek().direction == 'R') {
                    Robot top = stack.pop();
                    if (top.health > robot.health) {
                        top.health -= 1;
                        robot = null;
                        stack.push(top);
                        break;
                    } else if (top.health < robot.health) {
                        robot.health -= 1;
                    } else {
                        robot = null;
                        break;
                    }
                }
                if (robot != null) {
                    stack.push(robot);
                }
            }
        });
        return stack.stream().sorted(Comparator.comparingInt(r -> r.position)).mapToInt(r -> r.health).toArray();
    }

    class Robot {
        int position;
        int health;
        char direction;

        Robot(int position, int health, char direction) {
            this.position = position;
            this.health = health;
            this.direction = direction;
        }
    }
}

解释

方法:

这个算法首先通过对机器人的位置进行排序,以便按照位置顺序处理它们的移动和碰撞。使用一个栈来跟踪所有向右移动的机器人。当遇到向左移动的机器人时,检查栈顶的向右移动的机器人是否与之碰撞。如果发生碰撞,比较两个机器人的健康度,健康度较低的机器人被移除。如果健康度相同,则两者都被移除。栈用于跟踪仍然在移动的机器人,以便可以继续处理后续可能的碰撞。最后,返回所有幸存机器人的健康度。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在处理机器人移动和碰撞时需要对机器人的位置进行排序?
排序机器人的位置是为了按照它们在一维空间中的实际顺序处理它们的移动和相遇。这样做可以确保当处理每个机器人时,所有在它前面的机器人都已经被考虑过,从而正确地模拟它们的相对移动和潜在碰撞。如果不排序,可能会导致处理顺序错误,从而忽略或错误处理某些碰撞。
🦆
在代码中使用栈来跟踪向右移动的机器人,这种方法如何确保处理了所有可能的碰撞?
在代码中用栈来跟踪向右移动的机器人,可以高效管理和处理碰撞。当遇到向左移动的机器人时,算法会检查栈顶的机器人(即最近的向右移动的机器人)。如果存在碰撞,根据它们的健康度处理碰撞结果,并可能从栈中移除机器人。这种方式确保了只要栈中有向右移动的机器人,就会与之后遇到的每一个向左移动的机器人进行碰撞检查,从而保证处理了所有可能的碰撞。
🦆
在处理碰撞时,如果栈顶的机器人健康度高于当前处理的向左移动的机器人,为什么只减少栈顶机器人的健康度而不是移除它?
在处理碰撞时,如果栈顶的机器人健康度(向右移动的机器人)高于当前处理的向左移动的机器人,只减少栈顶机器人的健康度而不立即移除它是因为栈顶机器人的剩余健康度仍然可能足以参与后续的碰撞。完全移除一个健康度未耗尽的机器人会导致错误地忽略其对其他机器人的潜在影响。
🦆
算法中对于向左移动的机器人,如何判断其与栈顶机器人(向右移动的机器人)之间是否会发生碰撞?
在这个算法实现中,由于向左移动的机器人在处理时会与栈中的每一个向右移动的机器人(即栈顶开始)进行比较,实际上在逻辑上我们假设所有向左的机器人与它们遇到的任何向右的机器人都会发生碰撞。这是因为我们已经通过位置排序确保了机器人的相对位置,而栈中的机器人则是按照它们在空间中的位置顺序被处理,所以每个向左的机器人在遇到栈中向右的机器人时,都是在模拟一个潜在的碰撞事件。

相关问题