Skip to content

Commit dbf56b5

Browse files
committed
Add solution 0909
1 parent 127b852 commit dbf56b5

26 files changed

+604
-284
lines changed

README.md

Lines changed: 181 additions & 177 deletions
Large diffs are not rendered by default.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package leetcode
2+
3+
type pair struct {
4+
id, step int
5+
}
6+
7+
func snakesAndLadders(board [][]int) int {
8+
n := len(board)
9+
visited := make([]bool, n*n+1)
10+
queue := []pair{{1, 0}}
11+
for len(queue) > 0 {
12+
p := queue[0]
13+
queue = queue[1:]
14+
for i := 1; i <= 6; i++ {
15+
nxt := p.id + i
16+
if nxt > n*n { // 超出边界
17+
break
18+
}
19+
r, c := getRowCol(nxt, n) // 得到下一步的行列
20+
if board[r][c] > 0 { // 存在蛇或梯子
21+
nxt = board[r][c]
22+
}
23+
if nxt == n*n { // 到达终点
24+
return p.step + 1
25+
}
26+
if !visited[nxt] {
27+
visited[nxt] = true
28+
queue = append(queue, pair{nxt, p.step + 1}) // 扩展新状态
29+
}
30+
}
31+
}
32+
return -1
33+
}
34+
35+
func getRowCol(id, n int) (r, c int) {
36+
r, c = (id-1)/n, (id-1)%n
37+
if r%2 == 1 {
38+
c = n - 1 - c
39+
}
40+
r = n - 1 - r
41+
return r, c
42+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package leetcode
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
type question909 struct {
9+
para909
10+
ans909
11+
}
12+
13+
// para 是参数
14+
// one 代表第一个参数
15+
type para909 struct {
16+
one [][]int
17+
}
18+
19+
// ans 是答案
20+
// one 代表第一个答案
21+
type ans909 struct {
22+
one int
23+
}
24+
25+
func Test_Problem909(t *testing.T) {
26+
qs := []question909{
27+
{
28+
para909{[][]int{
29+
{-1, -1, -1, -1, -1, -1},
30+
{-1, -1, -1, -1, -1, -1},
31+
{-1, -1, -1, -1, -1, -1},
32+
{-1, 35, -1, -1, 13, -1},
33+
{-1, -1, -1, -1, -1, -1},
34+
{-1, 15, -1, -1, -1, -1},
35+
}},
36+
ans909{4},
37+
},
38+
}
39+
fmt.Printf("------------------------Leetcode Problem 909------------------------\n")
40+
for _, q := range qs {
41+
_, p := q.ans909, q.para909
42+
fmt.Printf("【input】:%v 【output】:%v\n", p, snakesAndLadders(p.one))
43+
}
44+
fmt.Printf("\n\n\n")
45+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# [909. Snakes and Ladders](https://leetcode.com/problems/snakes-and-ladders/)
2+
3+
4+
## 题目
5+
6+
On an N x N `board`, the numbers from `1` to `N*N` are written *boustrophedonically* **starting from the bottom left of the board**, and alternating direction each row.  For example, for a 6 x 6 board, the numbers are written as follows:
7+
8+
9+
![](https://assets.leetcode.com/uploads/2018/09/23/snakes.png)
10+
11+
You start on square `1` of the board (which is always in the last row and first column).  Each move, starting from square `x`, consists of the following:
12+
13+
- You choose a destination square `S` with number `x+1``x+2``x+3``x+4``x+5`, or `x+6`, provided this number is `<= N*N`.
14+
- (This choice simulates the result of a standard 6-sided die roll: ie., there are always **at most 6 destinations, regardless of the size of the board**.)
15+
- If `S` has a snake or ladder, you move to the destination of that snake or ladder. Otherwise, you move to `S`.
16+
17+
A board square on row `r` and column `c` has a "snake or ladder" if `board[r][c] != -1`.  The destination of that snake or ladder is `board[r][c]`.
18+
19+
Note that you only take a snake or ladder at most once per move: if the destination to a snake or ladder is the start of another snake or ladder, you do **not** continue moving.  (For example, if the board is `[[4,-1],[-1,3]]`, and on the first move your destination square is `2`, then you finish your first move at `3`, because you do **not** continue moving to `4`.)
20+
21+
Return the least number of moves required to reach square N*N.  If it is not possible, return `-1`.
22+
23+
**Example 1:**
24+
25+
```
26+
Input:[
27+
[-1,-1,-1,-1,-1,-1],
28+
[-1,-1,-1,-1,-1,-1],
29+
[-1,-1,-1,-1,-1,-1],
30+
[-1,35,-1,-1,13,-1],
31+
[-1,-1,-1,-1,-1,-1],
32+
[-1,15,-1,-1,-1,-1]]
33+
Output:4
34+
Explanation:
35+
At the beginning, you start at square 1 [at row 5, column 0].
36+
You decide to move to square 2, and must take the ladder to square 15.
37+
You then decide to move to square 17 (row 3, column 5), and must take the snake to square 13.
38+
You then decide to move to square 14, and must take the ladder to square 35.
39+
You then decide to move to square 36, ending the game.
40+
It can be shown that you need at least 4 moves to reach the N*N-th square, so the answer is 4.
41+
42+
```
43+
44+
**Note:**
45+
46+
1. `2 <= board.length = board[0].length <= 20`
47+
2. `board[i][j]` is between `1` and `N*N` or is equal to `1`.
48+
3. The board square with number `1` has no snake or ladder.
49+
4. The board square with number `N*N` has no snake or ladder.
50+
51+
## 题目大意
52+
53+
N x N 的棋盘 board 上,按从 1 到 N*N 的数字给方格编号,编号 从左下角开始,每一行交替方向。r 行 c 列的棋盘,按前述方法编号,棋盘格中可能存在 “蛇” 或 “梯子”;如果 board[r][c] != -1,那个蛇或梯子的目的地将会是 board[r][c]。玩家从棋盘上的方格 1 (总是在最后一行、第一列)开始出发。每一回合,玩家需要从当前方格 x 开始出发,按下述要求前进:选定目标方格:
54+
55+
- 选择从编号 x+1,x+2,x+3,x+4,x+5,或者 x+6 的方格中选出一个目标方格 s ,目标方格的编号 <= N*N。该选择模拟了掷骰子的情景,无论棋盘大小如何,你的目的地范围也只能处于区间 [x+1, x+6] 之间。
56+
- 传送玩家:如果目标方格 S 处存在蛇或梯子,那么玩家会传送到蛇或梯子的目的地。否则,玩家传送到目标方格 S。
57+
58+
注意,玩家在每回合的前进过程中最多只能爬过蛇或梯子一次:就算目的地是另一条蛇或梯子的起点,你也不会继续移动。返回达到方格 N*N 所需的最少移动次数,如果不可能,则返回 -1。
59+
60+
## 解题思路
61+
62+
- 这一题可以抽象为在有向图上求下标 1 的起点到下标 `N^2` 的终点的最短路径。用广度优先搜索。棋盘可以抽象成一个包含 `N^2` 个节点的有向图,对于每个节点 `x`,若 `x+i (1 ≤ i ≤ 6)` 上没有蛇或梯子,则连一条从 `x``x+i` 的有向边;否则记蛇梯的目的地为 `y`,连一条从 `x``y` 的有向边。然后按照最短路径的求解方式便可解题。时间复杂度 O(n^2),空间复杂度 O(n^2)。
63+
- 此题棋盘上的下标是蛇形的,所以遍历下一个点的时候需要转换坐标。具体做法根据行的奇偶性,行号为偶数,下标从左往右,行号为奇数,下标从右往左。具体实现见 `getRowCol()` 函数。
64+
65+
## 代码
66+
67+
```go
68+
package leetcode
69+
70+
type pair struct {
71+
id, step int
72+
}
73+
74+
func snakesAndLadders(board [][]int) int {
75+
n := len(board)
76+
visited := make([]bool, n*n+1)
77+
queue := []pair{{1, 0}}
78+
for len(queue) > 0 {
79+
p := queue[0]
80+
queue = queue[1:]
81+
for i := 1; i <= 6; i++ {
82+
nxt := p.id + i
83+
if nxt > n*n { // 超出边界
84+
break
85+
}
86+
r, c := getRowCol(nxt, n) // 得到下一步的行列
87+
if board[r][c] > 0 { // 存在蛇或梯子
88+
nxt = board[r][c]
89+
}
90+
if nxt == n*n { // 到达终点
91+
return p.step + 1
92+
}
93+
if !visited[nxt] {
94+
visited[nxt] = true
95+
queue = append(queue, pair{nxt, p.step + 1}) // 扩展新状态
96+
}
97+
}
98+
}
99+
return -1
100+
}
101+
102+
func getRowCol(id, n int) (r, c int) {
103+
r, c = (id-1)/n, (id-1)%n
104+
if r%2 == 1 {
105+
c = n - 1 - c
106+
}
107+
r = n - 1 - r
108+
return r, c
109+
}
110+
```

website/content/ChapterFour/0900~0999/0907.Sum-of-Subarray-Minimums.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,5 @@ func sumSubarrayMins2(A []int) int {
127127
----------------------------------------------
128128
<div style="display: flex;justify-content: space-between;align-items: center;">
129129
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0904.Fruit-Into-Baskets/">⬅️上一页</a></p>
130-
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0910.Smallest-Range-II/">下一页➡️</a></p>
130+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0909.Snakes-and-Ladders/">下一页➡️</a></p>
131131
</div>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# [909. Snakes and Ladders](https://leetcode.com/problems/snakes-and-ladders/)
2+
3+
4+
## 题目
5+
6+
On an N x N `board`, the numbers from `1` to `N*N` are written *boustrophedonically* **starting from the bottom left of the board**, and alternating direction each row.  For example, for a 6 x 6 board, the numbers are written as follows:
7+
8+
9+
![](https://assets.leetcode.com/uploads/2018/09/23/snakes.png)
10+
11+
You start on square `1` of the board (which is always in the last row and first column).  Each move, starting from square `x`, consists of the following:
12+
13+
- You choose a destination square `S` with number `x+1``x+2``x+3``x+4``x+5`, or `x+6`, provided this number is `<= N*N`.
14+
- (This choice simulates the result of a standard 6-sided die roll: ie., there are always **at most 6 destinations, regardless of the size of the board**.)
15+
- If `S` has a snake or ladder, you move to the destination of that snake or ladder. Otherwise, you move to `S`.
16+
17+
A board square on row `r` and column `c` has a "snake or ladder" if `board[r][c] != -1`.  The destination of that snake or ladder is `board[r][c]`.
18+
19+
Note that you only take a snake or ladder at most once per move: if the destination to a snake or ladder is the start of another snake or ladder, you do **not** continue moving.  (For example, if the board is `[[4,-1],[-1,3]]`, and on the first move your destination square is `2`, then you finish your first move at `3`, because you do **not** continue moving to `4`.)
20+
21+
Return the least number of moves required to reach square N*N.  If it is not possible, return `-1`.
22+
23+
**Example 1:**
24+
25+
```
26+
Input:[
27+
[-1,-1,-1,-1,-1,-1],
28+
[-1,-1,-1,-1,-1,-1],
29+
[-1,-1,-1,-1,-1,-1],
30+
[-1,35,-1,-1,13,-1],
31+
[-1,-1,-1,-1,-1,-1],
32+
[-1,15,-1,-1,-1,-1]]
33+
Output:4
34+
Explanation:
35+
At the beginning, you start at square 1 [at row 5, column 0].
36+
You decide to move to square 2, and must take the ladder to square 15.
37+
You then decide to move to square 17 (row 3, column 5), and must take the snake to square 13.
38+
You then decide to move to square 14, and must take the ladder to square 35.
39+
You then decide to move to square 36, ending the game.
40+
It can be shown that you need at least 4 moves to reach the N*N-th square, so the answer is 4.
41+
42+
```
43+
44+
**Note:**
45+
46+
1. `2 <= board.length = board[0].length <= 20`
47+
2. `board[i][j]` is between `1` and `N*N` or is equal to `1`.
48+
3. The board square with number `1` has no snake or ladder.
49+
4. The board square with number `N*N` has no snake or ladder.
50+
51+
## 题目大意
52+
53+
N x N 的棋盘 board 上,按从 1 到 N*N 的数字给方格编号,编号 从左下角开始,每一行交替方向。r 行 c 列的棋盘,按前述方法编号,棋盘格中可能存在 “蛇” 或 “梯子”;如果 board[r][c] != -1,那个蛇或梯子的目的地将会是 board[r][c]。玩家从棋盘上的方格 1 (总是在最后一行、第一列)开始出发。每一回合,玩家需要从当前方格 x 开始出发,按下述要求前进:选定目标方格:
54+
55+
- 选择从编号 x+1,x+2,x+3,x+4,x+5,或者 x+6 的方格中选出一个目标方格 s ,目标方格的编号 <= N*N。该选择模拟了掷骰子的情景,无论棋盘大小如何,你的目的地范围也只能处于区间 [x+1, x+6] 之间。
56+
- 传送玩家:如果目标方格 S 处存在蛇或梯子,那么玩家会传送到蛇或梯子的目的地。否则,玩家传送到目标方格 S。
57+
58+
注意,玩家在每回合的前进过程中最多只能爬过蛇或梯子一次:就算目的地是另一条蛇或梯子的起点,你也不会继续移动。返回达到方格 N*N 所需的最少移动次数,如果不可能,则返回 -1。
59+
60+
## 解题思路
61+
62+
- 这一题可以抽象为在有向图上求下标 1 的起点到下标 `N^2` 的终点的最短路径。用广度优先搜索。棋盘可以抽象成一个包含 `N^2` 个节点的有向图,对于每个节点 `x`,若 `x+i (1 ≤ i ≤ 6)` 上没有蛇或梯子,则连一条从 `x``x+i` 的有向边;否则记蛇梯的目的地为 `y`,连一条从 `x``y` 的有向边。然后按照最短路径的求解方式便可解题。时间复杂度 O(n^2),空间复杂度 O(n^2)。
63+
- 此题棋盘上的下标是蛇形的,所以遍历下一个点的时候需要转换坐标。具体做法根据行的奇偶性,行号为偶数,下标从左往右,行号为奇数,下标从右往左。具体实现见 `getRowCol()` 函数。
64+
65+
## 代码
66+
67+
```go
68+
package leetcode
69+
70+
type pair struct {
71+
id, step int
72+
}
73+
74+
func snakesAndLadders(board [][]int) int {
75+
n := len(board)
76+
visited := make([]bool, n*n+1)
77+
queue := []pair{{1, 0}}
78+
for len(queue) > 0 {
79+
p := queue[0]
80+
queue = queue[1:]
81+
for i := 1; i <= 6; i++ {
82+
nxt := p.id + i
83+
if nxt > n*n { // 超出边界
84+
break
85+
}
86+
r, c := getRowCol(nxt, n) // 得到下一步的行列
87+
if board[r][c] > 0 { // 存在蛇或梯子
88+
nxt = board[r][c]
89+
}
90+
if nxt == n*n { // 到达终点
91+
return p.step + 1
92+
}
93+
if !visited[nxt] {
94+
visited[nxt] = true
95+
queue = append(queue, pair{nxt, p.step + 1}) // 扩展新状态
96+
}
97+
}
98+
}
99+
return -1
100+
}
101+
102+
func getRowCol(id, n int) (r, c int) {
103+
r, c = (id-1)/n, (id-1)%n
104+
if r%2 == 1 {
105+
c = n - 1 - c
106+
}
107+
r = n - 1 - r
108+
return r, c
109+
}
110+
```
111+
112+
113+
----------------------------------------------
114+
<div style="display: flex;justify-content: space-between;align-items: center;">
115+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0907.Sum-of-Subarray-Minimums/">⬅️上一页</a></p>
116+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0910.Smallest-Range-II/">下一页➡️</a></p>
117+
</div>

website/content/ChapterFour/0900~0999/0910.Smallest-Range-II.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,6 @@ func min(a, b int) int {
8484

8585
----------------------------------------------
8686
<div style="display: flex;justify-content: space-between;align-items: center;">
87-
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0907.Sum-of-Subarray-Minimums/">⬅️上一页</a></p>
87+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0909.Snakes-and-Ladders/">⬅️上一页</a></p>
8888
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0900~0999/0911.Online-Election/">下一页➡️</a></p>
8989
</div>

0 commit comments

Comments
 (0)