题目链接
Leetcode.1824 最少侧跳次数
题目描述
给你一个长度为 n
的 3 跑道道路 ,它总共包含 n + 1
个 点 ,编号为 0 到 n 。一只青蛙从 0 号点第二条跑道 出发 ,它想要跳到点 n
处。然而道路上可能有一些障碍。
给你一个长度为 n + 1
的数组 obstacles
,其中 obstacles[i] (取值范围从 0 到 3)表示在点 i 处的 obstacles[i] 跑道上有一个障碍。如果
o
b
s
t
a
c
l
e
s
[
i
]
=
=
0
obstacles[i] == 0
obstacles[i]==0 ,那么点 i
处没有障碍。任何一个点的三条跑道中 最多有一个 障碍。
比方说,如果 o b s t a c l e s [ 2 ] = = 1 obstacles[2] == 1 obstacles[2]==1 ,那么说明在点 2 处跑道 1 有障碍。
这只青蛙从点 i
跳到点 i + 1
且跑道不变的前提是点 i + 1
的同一跑道上没有障碍。为了躲避障碍,这只青蛙也可以在 同一个 点处 侧跳 到 另外一条 跑道(这两条跑道可以不相邻),但前提是跳过去的跑道该点处没有障碍。
比方说,这只青蛙可以从点 3
处的跑道 3
跳到点 3
处的跑道 1
。
这只青蛙从点 0 处跑道 2 出发,并想到达点 n
处的 任一跑道 ,请你返回 最少侧跳次数 。
注意:点 0 处和点 n 处的任一跑道都不会有障碍。
示例 1:
输入:obstacles = [0,1,2,3,0]
输出:2
解释:最优方案如上图箭头所示。总共有 2 次侧跳(红色箭头)。
注意,这只青蛙只有当侧跳时才可以跳过障碍(如上图点 2 处所示)。
示例 2:
输入:obstacles = [0,1,1,3,3,0]
输出:0
解释:跑道 2 没有任何障碍,所以不需要任何侧跳。
提示:
- o b s t a c l e s . l e n g t h = = n + 1 obstacles.length == n + 1 obstacles.length==n+1
- 1 < = n < = 5 ∗ 1 0 5 1 <= n <= 5 * 10^5 1<=n<=5∗105
- 0 < = o b s t a c l e s [ i ] < = 3 0 <= obstacles[i] <= 3 0<=obstacles[i]<=3
- o b s t a c l e s [ 0 ] = = o b s t a c l e s [ n ] = = 0 obstacles[0] == obstacles[n] == 0 obstacles[0]==obstacles[n]==0
分析:
我们定义 f ( i , j ) f(i,j) f(i,j) 为,到达点 ( i , j ) (i,j) (i,j) 处的最小侧跳数。按照定义,最终返回的结果就为 m i n ( f ( n , 1 ) , f ( n , 2 ) , f ( n , 3 ) ) min(f(n,1),f(n,2),f(n,3)) min(f(n,1),f(n,2),f(n,3))。
- 如果当前点是障碍,那么将 f ( i , j ) f(i,j) f(i,j) 设置为 无穷大(只用设置为一个相对相对较大的数字即可,比如: 1 0 9 10^9 109)代表不可达
- 如果当前点不是障碍 并且 前一个点也不是障碍。那么 f ( i , j ) = f ( i − 1 , j ) f(i,j) = f(i-1,j) f(i,j)=f(i−1,j)
- 如果当前点不是障碍 但是 前一个点是障碍。那么,当 j = 1 时(也就是处于第一条跑道时, f ( i , 1 ) = m i n ( f ( i , 2 ) + 1 , f ( i , 3 ) + 1 ) f(i,1) = min(f(i,2)+1,f(i,3)+1) f(i,1)=min(f(i,2)+1,f(i,3)+1)(其他两条跑道也是类似操作),由其他两条跑道侧跳过来。
时间复杂度: O ( n ) O(n) O(n)
C++代码:
class Solution {
public:
int minSideJumps(vector<int>& obstacles) {
int n = obstacles.size();
int f[n+1][4];
memset(f,0,sizeof f);
int c = 2;
f[0][1] = 1,f[0][2] = 0,f[0][3] = 1;
for(int i = 1;i < n - 1;i++){
if(obstacles[i] == 0) continue;
else f[i][obstacles[i]] = 1e9;
}
for(int i = 1;i < n;i++){
for(int j = 1;j <= 3;j++){
if(obstacles[i-1] != j && obstacles[i] != j) f[i][j] = f[i-1][j];
}
if(obstacles[i-1] == 1 && obstacles[i] != 1) f[i][1] = min(f[i][2]+1,f[i][3]+1);
if(obstacles[i-1] == 2 && obstacles[i] != 2) f[i][2] = min(f[i][1]+1,f[i][3]+1);
if(obstacles[i-1] == 3 && obstacles[i] != 3) f[i][3] = min(f[i][1]+1,f[i][2]+1);
}
return min(f[n-1][1],min(f[n-1][2],f[n-1][3]));
}
};
Java代码:
class Solution {
public int minSideJumps(int[] obstacles) {
int n = obstacles.length;
int [][] f = new int[n][4];
//青蛙在第 0 点 的 第二条跑道上 所以 f[0][2] = 0
//另外两条跑道 可以由第二条跑道侧跳过去 所以是 1
f[0][1] = 1;
f[0][2] = 0;
f[0][3] = 1;
//将有障碍的位置初始化为 1e9 无穷大
for(int i = 1;i < n - 1;i++){
if(obstacles[i] == 0) continue;
else f[i][obstacles[i]] = 1000_000_000;
}
for(int i = 1;i < n;i++){
//处理 前一个点 和 当前点 都没有障碍的情况
for(int j = 1;j <= 3;j++){
if(obstacles[i-1] != j && obstacles[i] != j) f[i][j] = f[i-1][j];
}
//处理 前一个点有障碍 当前点没有障碍的情况 这个情况 只能由其他两条跑道侧跳过来
if(obstacles[i-1] == 1 && obstacles[i] != 1) f[i][1] = Math.min(f[i][2]+1,f[i][3]+1);
if(obstacles[i-1] == 2 && obstacles[i] != 2) f[i][2] = Math.min(f[i][1]+1,f[i][3]+1);
if(obstacles[i-1] == 3 && obstacles[i] != 3) f[i][3] = Math.min(f[i][1]+1,f[i][2]+1);
}
return Math.min(f[n-1][1],Math.min(f[n-1][2],f[n-1][3]));
}
}