/** * @param {number[][]} board * @return {number} */ const snakesAndLadders = function (board) { }; /* /* 把棋盘的每一个位置看成图的一个顶点,每一个顶点都有六个有向边指向后面的六个位置,也就是后面的六个顶点,有的顶点比较特殊, 它不指向后面的六个顶点,而是指向其他的顶点,我们要求的就是到达最后一个位置的顶点所需的最少步数,到这里我们很容易发现,这 是一个图的BFS题目,我们从最初的位置一层一层的往外扩,需要用几层就是几步, */ function f1(board) { // 定义一个长度为n*n+1的一维数组,将board压缩,减少计数难度 const n = board.length; const size = n * n; const arr = new Array(size + 1); // 0位置不需要,这样就能和board一一对应 let idx = 1; // 棋盘初始位置 let leftToRight = true; // s行遍历board for (let i = n - 1; i >= 0; i--) { if (leftToRight) { for (let j = 0; j < n; j++) { arr[idx++] = board[i][j]; } } else { for (let j = n - 1; j >= 0; j--) { arr[idx++] = board[i][j]; } } leftToRight = !leftToRight; } // bfs队列,从第一个位置开始,[1,0]表示,到达第一个位置最少只需要一步 const queue = [[1, 0]]; const visited = new Array(size + 1).fill(false); // 防止每一层的元素重复加入到下一层 visited[1] = true; while (queue.length) { const [cur, step] = queue.shift(); // 查看邻接的六个顶点 for (let i = 1; i <= 6; i++) { let next = cur + i; // 下一个顶点位置 // 越界,忽略这个顶点 if (next > size) { continue; } // 如果遇到蛇和梯子立即调整指定位置 if (arr[next] !== -1) { next = arr[next]; } // 如果邻接顶点就是目标位置,直接放回到达当前顶点的步数在加1 if (next === size) { return step + 1; } // 如果元素没有被访问将其加入队列,扩展下一层 if (!visited[next]) { visited[next] = true; queue.push([next, step + 1]); } } } return -1; // 不可达 } /* 将二维数组变成一维数组需要log(n*n)的时间复杂度,n为棋牌大小,相等于一开始就遍历了整个棋盘一遍,如果能实时计算当前位置,到其他位置 在board中的位置可以大大减少时间复杂度。 思考:假设我们有一个大小为n的棋牌,计数位置place(1 ~ n*n)在board中的坐标,首先计算行,行非常好计算,r = (place - 1) / n,那么列 还是 (place-1) % n吗?在这个题目不是的因为棋牌是按照s行走的,偶数行从左往右,奇数行从右往左,偶数行显然是(place-1)%n,那么技术行只需要将n 减去它即可 */ const id2rc = (id, n) => { const r = Math.floor((id - 1) / n); let c = (id - 1) % n; if (r % 2 === 1) { c = n - 1 - c; } return [n - 1 - r, c]; }; function f2(board) { const n = board.length; const size = n * n; // BFS const queue = [[1, 0]]; const visited = new Array(size + 1).fill(false); // 防止每一层的元素重复加入到下一层 visited[1] = true; while (queue.length) { const [cur, step] = queue.shift(); // 查看邻接的六个顶点 for (let i = 1; i <= 6; i++) { let next = cur + i; // 下一个顶点位置 // 越界,忽略这个顶点 if (next > size) { continue; } const [r, c] = id2rc(next, n); // 如果遇到蛇和梯子立即调整指定位置 if (board[r][c] !== -1) { next = board[r][c]; } // 如果邻接顶点就是目标位置,直接放回到达当前顶点的步数在加1 if (next === size) { return step + 1; } // 如果元素没有被访问将其加入队列,扩展下一层 if (!visited[next]) { visited[next] = true; queue.push([next, step + 1]); } } } return -1; // 不可达 }