跳转至

LCP 56. 信物传送

题目描述

欢迎各位勇者来到力扣城,本次试炼主题为「信物传送」。

本次试炼场地设有若干传送带,matrix[i][j] 表示第 ij 列的传送带运作方向,"^","v","<",">" 这四种符号分别表示 上、下、左、右 四个方向。信物会随传送带的方向移动。勇者每一次施法操作,可临时变更一处传送带的方向,在物品经过后传送带恢复原方向。 lcp (2).gif

通关信物初始位于坐标 start处,勇者需要将其移动到坐标 end 处,请返回勇者施法操作的最少次数。

注意:

  • startend 的格式均为 [i,j]

示例 1:

输入:matrix = [">>v","v^<","<><"], start = [0,1], end = [2,0]

输出:1

解释: 如上图所示 当信物移动到 [1,1] 时,勇者施法一次将 [1,1] 的传送方向 ^ 从变更为 < 从而信物移动到 [1,0],后续到达 end 位置 因此勇者最少需要施法操作 1 次

示例 2:

输入:matrix = [">>v",">>v","^<<"], start = [0,0], end = [1,1]

输出:0

解释:勇者无需施法,信物将自动传送至 end 位置

示例 3:

输入:matrix = [">^^>","<^v>","^v^<"], start = [0,0], end = [1,3]

输出:3

提示:

  • matrix 中仅包含 '^'、'v'、'<'、'>'
  • 0 < matrix.length <= 100
  • 0 < matrix[i].length <= 100
  • 0 <= start[0],end[0] < matrix.length
  • 0 <= start[1],end[1] < matrix[i].length

解法

方法一:双端队列 BFS(0-1 BFS)

每走到一个格子 \((i, j)\),有 \(4\) 个方向可以走,如果方向与当前格子的方向相同,那么不需要施法,否则需要施法一次。

因此,我们可以使用 BFS 求出从起点到终点的最短路径。

我们定义一个双端队列 \(q\),存储当前可以到达的格子,每次从队首取出一个格子 \((i, j)\),然后向四个方向扩展,如果扩展的格子 \((x, y)\) 不需要施法,那么将其加入队首,否则加入队尾。当我们第一次到达终点时,就得到了最短路径。

时间复杂度 \(O(m \times n)\),空间复杂度 \(O(m \times n)\)。其中 \(m\)\(n\) 分别是矩阵的行数和列数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
    def conveyorBelt(self, matrix: List[str], start: List[int], end: List[int]) -> int:
        dirs = (-1, 0, 1, 0, -1)
        d = {"^": 0, "v": 2, "<": 3, ">": 1}
        i, j = start
        q = deque([(i, j)])
        m, n = len(matrix), len(matrix[0])
        dist = [[inf] * n for _ in range(m)]
        dist[i][j] = 0
        while 1:
            i, j = q.popleft()
            if i == end[0] and j == end[1]:
                return int(dist[i][j])
            for k in range(4):
                x, y = i + dirs[k], j + dirs[k + 1]
                t = dist[i][j] + int(k != d[matrix[i][j]])
                if 0 <= x < m and 0 <= y < n and t < dist[x][y]:
                    dist[x][y] = t
                    if dist[x][y] == dist[i][j]:
                        q.appendleft((x, y))
                    else:
                        q.append((x, y))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution {
    public int conveyorBelt(String[] matrix, int[] start, int[] end) {
        int[] dirs = {-1, 0, 1, 0, -1};
        Map<Character, Integer> d = new HashMap<>(4);
        d.put('^', 0);
        d.put('>', 1);
        d.put('v', 2);
        d.put('<', 3);
        Deque<int[]> q = new ArrayDeque<>();
        q.offer(new int[] {start[0], start[1]});
        int m = matrix.length, n = matrix[0].length();
        int[][] dist = new int[m][n];
        for (int[] row : dist) {
            Arrays.fill(row, 1 << 30);
        }
        dist[start[0]][start[1]] = 0;
        while (true) {
            int[] p = q.poll();
            int i = p[0], j = p[1];
            if (i == end[0] && j == end[1]) {
                return dist[i][j];
            }
            for (int k = 0; k < 4; ++k) {
                int x = i + dirs[k], y = j + dirs[k + 1];
                int t = dist[i][j] + (k == d.get(matrix[i].charAt(j)) ? 0 : 1);
                if (x >= 0 && x < m && y >= 0 && y < n && t < dist[x][y]) {
                    dist[x][y] = t;
                    if (dist[x][y] == dist[i][j]) {
                        q.offerFirst(new int[] {x, y});
                    } else {
                        q.offerLast(new int[] {x, y});
                    }
                }
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
public:
    int conveyorBelt(vector<string>& matrix, vector<int>& start, vector<int>& end) {
        int dirs[5] = {-1, 0, 1, 0, -1};
        unordered_map<char, int> d;
        d['^'] = 0;
        d['>'] = 1;
        d['v'] = 2;
        d['<'] = 3;
        deque<pair<int, int>> q;
        q.emplace_back(start[0], start[1]);
        int m = matrix.size(), n = matrix[0].size();
        int dist[m][n];
        memset(dist, 0x3f, sizeof(dist));
        dist[start[0]][start[1]] = 0;
        while (1) {
            auto [i, j] = q.front();
            q.pop_front();
            if (i == end[0] && j == end[1]) {
                return dist[i][j];
            }
            for (int k = 0; k < 4; ++k) {
                int x = i + dirs[k], y = j + dirs[k + 1];
                int t = dist[i][j] + (k == d[matrix[i][j]] ? 0 : 1);
                if (x >= 0 && x < m && y >= 0 && y < n && t < dist[x][y]) {
                    dist[x][y] = t;
                    if (dist[x][y] == dist[i][j]) {
                        q.emplace_front(x, y);
                    } else {
                        q.emplace_back(x, y);
                    }
                }
            }
        }
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
func conveyorBelt(matrix []string, start []int, end []int) int {
    dirs := [5]int{-1, 0, 1, 0, -1}
    d := map[byte]int{
        '^': 0,
        '>': 1,
        'v': 2,
        '<': 3,
    }
    q := [][2]int{[2]int{start[0], start[1]}}
    m, n := len(matrix), len(matrix[0])
    dist := make([][]int, m)
    for i := range dist {
        dist[i] = make([]int, n)
        for j := range dist[i] {
            dist[i][j] = 1 << 30
        }
    }
    dist[start[0]][start[1]] = 0
    for {
        p := q[0]
        i, j := p[0], p[1]
        if i == end[0] && j == end[1] {
            return dist[i][j]
        }
        q = q[1:]
        for k := 0; k < 4; k++ {
            x, y := i+dirs[k], j+dirs[k+1]
            t := dist[i][j]
            if k != d[matrix[i][j]] {
                t++
            }
            if x >= 0 && x < m && y >= 0 && y < n && t < dist[x][y] {
                dist[x][y] = t
                if dist[x][y] == dist[i][j] {
                    q = append([][2]int{[2]int{x, y}}, q...)
                } else {
                    q = append(q, [2]int{x, y})
                }
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function conveyorBelt(matrix: string[], start: number[], end: number[]): number {
    const dirs = [-1, 0, 1, 0, -1];
    const d: Map<string, number> = new Map();
    d.set('^', 0);
    d.set('>', 1);
    d.set('v', 2);
    d.set('<', 3);
    const q: number[][] = [start];
    const m = matrix.length;
    const n = matrix[0].length;
    const dist: number[][] = Array(m)
        .fill(0)
        .map(() => Array(n).fill(1 << 30));
    dist[start[0]][start[1]] = 0;
    while (true) {
        const [i, j] = q.shift()!;
        if (i === end[0] && j === end[1]) {
            return dist[i][j];
        }
        for (let k = 0; k < 4; ++k) {
            const x = i + dirs[k];
            const y = j + dirs[k + 1];
            const t = dist[i][j] + (d.get(matrix[i][j]) === k ? 0 : 1);
            if (x >= 0 && x < m && y >= 0 && y < n && t < dist[x][y]) {
                dist[x][y] = t;
                if (t == dist[i][j]) {
                    q.unshift([x, y]);
                } else {
                    q.push([x, y]);
                }
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
    func conveyorBelt(_ matrix: [String], _ start: [Int], _ end: [Int]) -> Int {
        let directions: [(Int, Int)] = [(-1, 0), (0, 1), (1, 0), (0, -1)]
        let directionMap: [Character: Int] = ["^": 0, ">": 1, "v": 2, "<": 3]

        let rows = matrix.count
        let cols = matrix[0].count

        var dist = Array(repeating: Array(repeating: Int.max, count: cols), count: rows)
        var deque: [(Int, Int)] = []

        dist[start[0]][start[1]] = 0
        deque.append((start[0], start[1]))

        while !deque.isEmpty {
            let (i, j) = deque.removeFirst()

            if i == end[0] && j == end[1] {
                return dist[i][j]
            }

            for (k, (di, dj)) in directions.enumerated() {
                let ni = i + di
                let nj = j + dj

                if ni >= 0 && ni < rows && nj >= 0 && nj < cols {
                    let currentChar = matrix[i][matrix[i].index(matrix[i].startIndex, offsetBy: j)]
                    let additionalCost = directionMap[currentChar] == k ? 0 : 1
                    let newDist = dist[i][j] + additionalCost

                    if newDist < dist[ni][nj] {
                        dist[ni][nj] = newDist

                        if additionalCost == 0 {
                            deque.insert((ni, nj), at: 0)
                        } else {
                            deque.append((ni, nj))
                        }
                    }
                }
            }
        }

        return -1
    }
}

评论