Featured image of post Snakes And Ladders

Snakes And Ladders

909. 蛇梯棋

分析

  1. 坐标与编号的映射
    • 根据题目中的「转行交替方式」编号规则,从左下角开始生成一个 id 数组,表示棋盘位置与编号的对应关系
    • 还需要记录每个编号对应的二维坐标 cord,便于查找棋盘上的位置
  2. 广度优先搜索(BFS)
    • 用队列维护当前可以到达的位置
    • 每次模拟掷骰子,从当前编号 k 出发,考虑 [k+1, \min(k+6, n^2)] 范围内的目标编号
    • 如果目标编号存在梯子或蛇(即 board[x][y] != -1),直接跳转到指定位置。
  3. 终止条件
    • 如果当前编号是 n^2,直接返回当前步数
    • 若队列为空仍未到达终点,返回 -1,表示无法到达终点

时间复杂度

  • 构建编号与坐标映射需要 O(n^2)
  • BFS 遍历每个节点,并检查最多 6 条边,复杂度为 O(n^2)

总时间复杂度 O(n^2)

空间复杂度

  • 存储坐标映射和队列所需空间均为 O(n^2)

总空间复杂度为 O(n^2)

C++代码

 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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class Solution
{
public:
    #define x first
    #define y second
    int snakesAndLadders(vector<vector<int>>& board)
    {
        int n = board.size();
        // 记录编号与坐标的映射
        std::vector<std::vector<int>> id(n, std::vector<int>(n));
        using PII = std::pair<int, int>;
        std::vector<PII> cord(n * n + 1);

        // 生成棋盘编号与坐标的映射
        int k = 1, direct = 0;
        for (int i = n - 1; i >= 0; --i)
        {
            if (direct % 2 == 0)
            { // 从左到右
                for (int j = 0; j < n; ++j)
                {
                    id[i][j] = k;
                    cord[k] = {i, j};
                    ++k;
                }
            }
            else
            { // 从右到左
                for (int j = n - 1; j >= 0; --j)
                {
                    id[i][j] = k;
                    cord[k] = {i, j};
                    ++k;
                }
            }
            ++ direct;
        }

        // BFS 寻找最短路径
        std::queue<PII> q;
        std::vector<std::vector<int>> dist(n, std::vector<int>(n, 1e9));
        q.push({n - 1, 0}); // 从起点开始
        dist[n - 1][0] = 0;

        while (!q.empty())
        {
            PII t = q.front();
            q.pop();

            int k = id[t.x][t.y]; // 当前编号
            if (k == n * n) // 到达终点
                return dist[t.x][t.y];

            for (int i = k + 1; i <= k + 6 && i <= n * n; ++i)
            {
                int x = cord[i].x, y = cord[i].y;
                if (board[x][y] == -1)
                { // 无蛇无梯子
                    if (dist[x][y] > dist[t.x][t.y] + 1)
                    {
                        dist[x][y] = dist[t.x][t.y] + 1;
                        q.push({x, y});
                    }
                }
                else
                { // 存在蛇或梯子
                    int ladder = board[x][y];
                    x = cord[ladder].x, y = cord[ladder].y;
                    if (dist[x][y] > dist[t.x][t.y] + 1)
                    {
                        dist[x][y] = dist[t.x][t.y] + 1;
                        q.push({x, y});
                    }
                }
            }
        }
        return -1; // 无法到达终点
    }
};
Built with Hugo
Theme Stack designed by Jimmy