LCP 43-十字路口的交通
前往「力扣挑战赛」场馆的道路上,有一个拥堵的十字路口,该十字路口由两条双向两车道的路交叉构成。由于信号灯故障,交警需要手动指挥拥堵车辆。假定路口没有新的来车且一辆车从一个车道驶入另一个车道所需的时间恰好为一秒钟,长度为
4 的一维字符串数组 directions
中按照 东、南、西、北 顺序记录了四个方向从最靠近路口到最远离路口的车辆计划开往的方向。其中: -"E"
表示向东行驶; - "S"
表示向南行驶; - "W"
表示向西行驶; - "N"
表示向北行驶。
交警每秒钟只能指挥各个车道距离路口最近的一辆车,且每次指挥需要满足如下规则: - 同一秒钟内,一个方向的车道只允许驶出一辆车; -
同一秒钟内,一个方向的车道只允许驶入一辆车; - 同一秒钟内,车辆的行驶路线不可相交。 请返回最少需要几秒钟,该十字路口等候的车辆才能全部走完。
各个车道驶出的车辆可能的行驶路线如图所示: ![图片.png](https://pic.leetcode-
cn.com/1630393755-gyPeMM-%E5%9B%BE%E7%89%87.png){:height=”350px”} 注意: -
测试数据保证不会出现掉头行驶指令,即某一方向的行驶车辆计划开往的方向不会是当前车辆所在的车道的方向; - 表示堵塞车辆行驶方向的字符串仅用大写字母"E"
,"N"
,"W"
,"S"
表示。 示例 1: >输入:directions = ["W","N","ES","W"]
>
输出:
2
> >解释: >第 1 秒:东西方向排在最前的车先行,剩余车辆状态["","N","S","W"]
; >第 2
秒:南、西、北方向的车行驶,路口无等待车辆; >因此最少需要 2 秒,返回 2。 示例 2: >输入:directions = ["NS","WE","SE","EW"]
> >输出:3
> >解释: >第 1 秒:四个方向排在最前的车均可驶出; >第 2
秒:东南方向的车驶出,剩余车辆状态["","","E","W"]
; >第 3 秒:西北方向的车驶出。 提示: -directions.length = 4
-0 <= directions[i].length <= 20
【使用的算法】
- 动态规划。
- 位运算。
【计算步骤】
- 设输入的
char *direction[4]
的四个字符串的长度依次为len0
、len1
、len2
和len3
。其中0
、1
、2
、3
依次表示东南西北四个方向。 - 定义一个四维数组,
dp[1 + len0][1 + len1][1 + len2][1 + len3]
,其中,dp[x[0]][x[1]][x[2]][x[3]]
表示四个方向依次剩余x[0]
、x[1]
、x[2]
和x[3]
辆车的时候,最少的通行时间。
当方向i
剩余x[i]
辆车的时候,排在路口的那辆车在数组中的下标为index[i] = leni - x[i]
,当x[i] == 0
,即index[i] == leni
的时候,表示这个方向没有任何剩余车辆了。
最终要得到的结果,就是dp[len0][len1][len2][len3]
。
边界条件为:dp[0][0][0][0] = 0
,即没有任何剩余车辆时,需要的时间为0
。 - 用一个二进制掩码
t
来记录dp[x[0]][x[1]][x[2]][x[3]]
对应的四个方向的路口,是否还有剩余车辆。
掩码右数第i
位比特(从第0
开始计)用来表示这个方向i
是否还有剩余车辆,该位为1
表示有剩余车辆。
遍历这个掩码的每一个非空子集mask
,即选中这个掩码中的一部分车辆进行通行:
(1) 如果选中的这些车辆,相互的行进方向产生了冲突,即行进路线有相交,或者驶入同一个目标车道,则忽略这一次的子集。
(2) 如果选中的这些车辆,相互的行进方向互不冲突,则这一秒钟作为这个子集的车辆的行进耗时,各个方向上还剩余y[0]
、y[1]
、y[2]
和y[3]
辆车,于是可得:dp[x[0]][x[1]][x[2]][x[3]] = MIN_VAL(dp[x[0]][x[1]][x[2]][x[3]], 1 + dp[y[0]][y[1]][y[2]][y[3]]);
这里:如果选中的子集中,包含了方向i
的车辆,y[i] = x[i] - 1
,否则,y[i] = x[i]
,用位运算的表达方式是:y[i] = (1 << i & mask) ? x[i] - 1 : x[i];
- 上面第3步中提到了,需要判断选中的某个子集,各辆车的行进方向是否产生冲突。这里将输入的原始字符串数组
direction[4]
进行归一化处理,即将原数组中出现的绝对方向东南西北(即”ESWN”四个字母),转换成相对方向左前右,即left
、straight
、right
三个词的首字母”LSR”,记录在数组dir[4]
里。
如此,对于任意一个方向的车辆,都可以归一化处理。
(1) 当这个方向的车辆需要左转时,会和左向来的“直行或左转”车辆、对向来的“直行或右转”车辆、右向来的“直行或左转”车辆产生冲突。
(2) 当这个方向的车辆需要直行时,会和左向来的“直行或左转”车辆、对向来的“左转”车辆、右向来的“所有”车辆产生冲突。
(3) 当这个方向的车辆需要右转时,会和左向来的“直行”车辆、对向来的“左转”车辆产生冲突。
{:width=400}
【代码】
1 | #define MIN_VAL(x, y) ((x) < (y) ? (x) : (y)) |