leetcode
leetcode 3051 ~ 3100
十字路口的交通

十字路口的交通

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 4296 ms, 内存: 58.8 MB


/*
 * 思路:
 * 1. 每秒钟只能指挥各个车道距离路口最近的一辆车,且每次指挥需要满足如下规则:
 *    - 同一秒钟内,一个方向的车道只允许驶出一辆车;
 *    - 同一秒钟内,一个方向的车道只允许驶入一辆车;
 *    - 同一秒钟内,车辆的行驶路线不可相交。
 * 2. 使用四个队列分别表示东南西北四个方向的车辆队列。
 * 3. 每秒钟检查四个队列是否可以同时出队并记录秒数。
 * 4. 直到所有队列为空,返回总秒数。
 */

import java.util.LinkedList;
import java.util.Queue;
import java.util.stream.IntStream;

public class TrafficCrossing {
    public int minTimeToClear(String[] directions) {
        Queue<Character>[] queues = new Queue[4];
        IntStream.range(0, 4).forEach(i -> {
            queues[i] = new LinkedList<>();
            directions[i].chars().forEach(c -> queues[i].offer((char) c));
        });

        int seconds = 0;
        while (IntStream.range(0, 4).anyMatch(i -> !queues[i].isEmpty())) {
            boolean[] proceed = new boolean[4];

            IntStream.range(0, 4).forEach(i -> {
                if (!queues[i].isEmpty()) {
                    char dest = queues[i].peek();
                    if ((i == 0 && dest == 'W') || (i == 1 && dest == 'N') ||
                        (i == 2 && dest == 'E') || (i == 3 && dest == 'S')) {
                        proceed[i] = true;
                    }
                }
            });

            IntStream.range(0, 4).forEach(i -> {
                if (proceed[i]) queues[i].poll();
            });

            seconds++;
        }

        return seconds;
    }
}

解释

方法:

该题解采用了递归加备忘录的方法来解决问题,涉及动态规划的思路。具体思路如下:首先,对每个方向的车辆数进行统计,并定义两个缓存函数。第一个缓存函数`can_pass`用于检查在不产生冲突的情况下哪些车可以同时通过交叉口。它使用了一个16位的数组来标记可能的冲突,并对每一种行驶方向的车辆进行冲突检查。第二个缓存函数`get_min_time`是主要的递归函数,用于计算清空路口所需的最短时间。它首先考虑一个车辆通过的情况,然后尝试所有可能的车辆组合,递归地计算通过剩余车辆所需的时间。这里使用了组合生成和对每种可能的行车情况进行模拟,通过调用`can_pass`来确保没有冲突。

时间复杂度:

O(2^n)

空间复杂度:

O(n + 4^n)

代码细节讲解

🦆
在函数`can_pass`中,如何确保处理的16种车辆动作组合都正确反映了交通规则?
函数`can_pass`通过一个16位的数组`op`来记录和管理冲突。每一位代表一个特定的车辆方向和目标方向的组合。例如,如果东边的车想向南行驶,这将会影响到其他可能与之冲突的路线(如其他车辆也想向南或交叉这条路线)。通过设置和检查这些位的状态,可以确保任何车辆行进的组合都不会违反交通规则。在实现时,需要确保每一种可能的车辆方向组合都被考虑到,并且对应的位正确地反映了是否会产生冲突。这样,通过逻辑检查和位操作来确保不会有违反交通规则的车辆组合被允许通过。
🦆
在同时尝试让多辆车通过的递归逻辑中,为什么选择了从2车开始尝试,而不是从更多车辆开始?
在递归逻辑中,从两辆车开始尝试主要是基于优化和实际场景的考虑。首先,单车通过是基本情况,必须先考虑。接着,从两辆车开始尝试是因为这是最简单的多车交互情况,可以有效地处理多数交通冲突和优化通行时间。如果直接从更多车辆开始,虽然可能在某些情况下更快,但会大幅增加复杂度和计算量,因为组合数量随车辆数量呈指数增长。因此,从两辆车开始,依次增加车辆数,是一个平衡计算效率和解决问题复杂度的实用方法。
🦆
在递归函数`get_min_time`中,如何确保每次递归调用都能正确更新车辆的剩余数量并避免错误地重复处理相同的车辆状态?
在`get_min_time`函数中,使用了一个元组`rest_idx`来记录每个方向剩余的车辆数量。这个元组在每次递归调用时都会被更新,以反映车辆通过交叉口后的新状态。使用列表推导和元组操作来确保每次只减少通过的车辆数,而不影响未通过的车辆。此外,使用`lru_cache`装饰器对这个函数进行了缓存,可以避免重复计算相同的车辆状态,从而提高效率和防止错误重复处理。这种方法确保了状态的正确更新和高效的递归调用。

相关问题