Add solution 1293、2096

This commit is contained in:
halfrost
2022-09-02 20:20:20 +08:00
parent 200b30895c
commit 984772f724
9 changed files with 719 additions and 2 deletions

View File

@ -0,0 +1,71 @@
package leetcode
var dir = [][]int{
{-1, 0},
{0, 1},
{1, 0},
{0, -1},
}
type pos struct {
x, y int
obstacle int
step int
}
func shortestPath(grid [][]int, k int) int {
queue, m, n := []pos{}, len(grid), len(grid[0])
visitor := make([][][]int, m)
if len(grid) == 1 && len(grid[0]) == 1 {
return 0
}
for i := 0; i < m; i++ {
visitor[i] = make([][]int, n)
for j := 0; j < n; j++ {
visitor[i][j] = make([]int, k+1)
}
}
visitor[0][0][0] = 1
queue = append(queue, pos{x: 0, y: 0, obstacle: 0, step: 0})
for len(queue) > 0 {
size := len(queue)
for size > 0 {
size--
node := queue[0]
queue = queue[1:]
for i := 0; i < len(dir); i++ {
newX := node.x + dir[i][0]
newY := node.y + dir[i][1]
if newX == m-1 && newY == n-1 {
if node.obstacle != 0 {
if node.obstacle <= k {
return node.step + 1
} else {
continue
}
}
return node.step + 1
}
if isInBoard(grid, newX, newY) {
if grid[newX][newY] == 1 {
if node.obstacle+1 <= k && visitor[newX][newY][node.obstacle+1] != 1 {
queue = append(queue, pos{x: newX, y: newY, obstacle: node.obstacle + 1, step: node.step + 1})
visitor[newX][newY][node.obstacle+1] = 1
}
} else {
if node.obstacle <= k && visitor[newX][newY][node.obstacle] != 1 {
queue = append(queue, pos{x: newX, y: newY, obstacle: node.obstacle, step: node.step + 1})
visitor[newX][newY][node.obstacle] = 1
}
}
}
}
}
}
return -1
}
func isInBoard(board [][]int, x, y int) bool {
return x >= 0 && x < len(board) && y >= 0 && y < len(board[0])
}

View File

@ -0,0 +1,73 @@
package leetcode
import (
"fmt"
"testing"
)
type question1293 struct {
para1293
ans1293
}
// para 是参数
// one 代表第一个参数
type para1293 struct {
grid [][]int
k int
}
// ans 是答案
// one 代表第一个答案
type ans1293 struct {
one int
}
func Test_Problem1293(t *testing.T) {
qs := []question1293{
{
para1293{[][]int{
{0, 0, 0},
}, 1},
ans1293{2},
},
{
para1293{[][]int{
{0, 1, 1}, {0, 1, 1}, {0, 0, 0}, {0, 1, 0}, {0, 1, 0},
}, 2},
ans1293{6},
},
{
para1293{[][]int{
{0, 0, 0}, {1, 1, 0}, {0, 0, 0}, {0, 1, 1}, {0, 0, 0},
}, 1},
ans1293{6},
},
{
para1293{[][]int{
{0, 1, 1}, {1, 1, 1}, {1, 0, 0},
}, 1},
ans1293{-1},
},
{
para1293{[][]int{
{0},
}, 1},
ans1293{0},
},
}
fmt.Printf("------------------------Leetcode Problem 1293------------------------\n")
for _, q := range qs {
_, p := q.ans1293, q.para1293
fmt.Printf("【input】:%v 【output】:%v\n", p, shortestPath(p.grid, p.k))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,131 @@
# [1293. Shortest Path in a Grid with Obstacles Elimination](https://leetcode.com/problems/shortest-path-in-a-grid-with-obstacles-elimination/)
## 题目
You are given an m x n integer matrix grid where each cell is either 0 (empty) or 1 (obstacle). You can move up, down, left, or right from and to an empty cell in one step.
Return the minimum number of steps to walk from the upper left corner (0, 0) to the lower right corner (m - 1, n - 1) given that you can eliminate at most k obstacles. If it is not possible to find such walk return -1.
Example 1:
![](https://assets.leetcode.com/uploads/2021/09/30/short1-grid.jpg)
```
Input: grid = [[0,0,0],[1,1,0],[0,0,0],[0,1,1],[0,0,0]], k = 1
Output: 6
Explanation:
The shortest path without eliminating any obstacle is 10.
The shortest path with one obstacle elimination at position (3,2) is 6. Such path is (0,0) -> (0,1) -> (0,2) -> (1,2) -> (2,2) -> (3,2) -> (4,2).
```
Example 2:
![](https://assets.leetcode.com/uploads/2021/09/30/short2-grid.jpg)
```
Input: grid = [[0,1,1],[1,1,1],[1,0,0]], k = 1
Output: -1
Explanation: We need to eliminate at least two obstacles to find such a walk.
```
Constraints:
- m == grid.length
- n == grid[i].length
- 1 <= m, n <= 40
- 1 <= k <= m * n
- grid[i][j] is either 0 or 1.
- grid[0][0] == grid[m - 1][n - 1] == 0
## 题目大意
给你一个 m * n 的网格其中每个单元格不是 0就是 1障碍物。每一步您都可以在空白单元格中上、下、左、右移动。
如果您 最多 可以消除 k 个障碍物,请找出从左上角 (0, 0) 到右下角 (m-1, n-1) 的最短路径,并返回通过该路径所需的步数。如果找不到这样的路径,则返回 -1 
## 解题思路
使用 BFS 遍历棋盘。这题比普通可达性问题多了一个障碍物的限制。这个也不难。每个点往周边四个方向扩展的时候,如果遇到障碍物,先算上这个障碍物,障碍物累积总个数小于 K 的时候,从障碍物的这个格子继续开始遍历。如果没有遇到障碍物,判断当前累积障碍物个数是否已经小于 K 个,如果小于 K 便继续遍历。如果大于 K便终止此轮遍历。
## 代码
```go
var dir = [][]int{
{-1, 0},
{0, 1},
{1, 0},
{0, -1},
}
type pos struct {
x, y int
obstacle int
step int
}
func shortestPath(grid [][]int, k int) int {
queue, m, n := []pos{}, len(grid), len(grid[0])
visitor := make([][][]int, m)
if len(grid) == 1 && len(grid[0]) == 1 {
return 0
}
for i := 0; i < m; i++ {
visitor[i] = make([][]int, n)
for j := 0; j < n; j++ {
visitor[i][j] = make([]int, k+1)
}
}
visitor[0][0][0] = 1
queue = append(queue, pos{x: 0, y: 0, obstacle: 0, step: 0})
for len(queue) > 0 {
size := len(queue)
for size > 0 {
size--
node := queue[0]
queue = queue[1:]
for i := 0; i < len(dir); i++ {
newX := node.x + dir[i][0]
newY := node.y + dir[i][1]
if newX == m-1 && newY == n-1 {
if node.obstacle != 0 {
if node.obstacle <= k {
return node.step + 1
} else {
continue
}
}
return node.step + 1
}
if isInBoard(grid, newX, newY) {
if grid[newX][newY] == 1 {
if node.obstacle+1 <= k && visitor[newX][newY][node.obstacle+1] != 1 {
queue = append(queue, pos{x: newX, y: newY, obstacle: node.obstacle + 1, step: node.step + 1})
visitor[newX][newY][node.obstacle+1] = 1
}
} else {
if node.obstacle <= k && visitor[newX][newY][node.obstacle] != 1 {
queue = append(queue, pos{x: newX, y: newY, obstacle: node.obstacle, step: node.step + 1})
visitor[newX][newY][node.obstacle] = 1
}
}
}
}
}
}
return -1
}
func isInBoard(board [][]int, x, y int) bool {
return x >= 0 && x < len(board) && y >= 0 && y < len(board[0])
}
```

View File

@ -0,0 +1,77 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/structures"
)
// TreeNode define
type TreeNode = structures.TreeNode
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func getDirections(root *TreeNode, startValue int, destValue int) string {
sPath, dPath := make([]byte, 0), make([]byte, 0)
findPath(root, startValue, &sPath)
findPath(root, destValue, &dPath)
size, i := min(len(sPath), len(dPath)), 0
for i < size {
if sPath[len(sPath)-1-i] == dPath[len(dPath)-1-i] {
i++
} else {
break
}
}
sPath = sPath[:len(sPath)-i]
replace(sPath)
dPath = dPath[:len(dPath)-i]
reverse(dPath)
sPath = append(sPath, dPath...)
return string(sPath)
}
func findPath(root *TreeNode, value int, path *[]byte) bool {
if root.Val == value {
return true
}
if root.Left != nil && findPath(root.Left, value, path) {
*path = append(*path, 'L')
return true
}
if root.Right != nil && findPath(root.Right, value, path) {
*path = append(*path, 'R')
return true
}
return false
}
func reverse(path []byte) {
left, right := 0, len(path)-1
for left < right {
path[left], path[right] = path[right], path[left]
left++
right--
}
}
func replace(path []byte) {
for i := 0; i < len(path); i++ {
path[i] = 'U'
}
}
func min(i, j int) int {
if i < j {
return i
}
return j
}

View File

@ -0,0 +1,68 @@
package leetcode
import (
"fmt"
"testing"
"github.com/halfrost/LeetCode-Go/structures"
)
type question2096 struct {
para2096
ans2096
}
// para 是参数
// one 代表第一个参数
type para2096 struct {
one []int
startValue int
destValue int
}
// ans 是答案
// one 代表第一个答案
type ans2096 struct {
one string
}
func Test_Problem2096(t *testing.T) {
qs := []question2096{
{
para2096{[]int{5, 1, 2, 3, structures.NULL, 6, 4}, 3, 6},
ans2096{"UURL"},
},
{
para2096{[]int{2, 1}, 2, 1},
ans2096{"L"},
},
{
para2096{[]int{1, 2}, 2, 1},
ans2096{"U"},
},
{
para2096{[]int{3, 1, 2}, 2, 1},
ans2096{"UL"},
},
{
para2096{[]int{7, 8, 3, 1, structures.NULL, 4, 5, 6, structures.NULL, structures.NULL, structures.NULL, structures.NULL, structures.NULL, structures.NULL, 2}, 7, 5},
ans2096{"RR"},
},
}
fmt.Printf("------------------------Leetcode Problem 2096------------------------\n")
for _, q := range qs {
_, p := q.ans2096, q.para2096
fmt.Printf("【input】:%v ", p)
root := structures.Ints2TreeNode(p.one)
fmt.Printf("【output】:%v \n", getDirections(root, p.startValue, p.destValue))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,145 @@
# [2096. Step-By-Step Directions From a Binary Tree Node to Another](https://leetcode.com/problems/step-by-step-directions-from-a-binary-tree-node-to-another/)
## 题目
You are given the `root` of a **binary tree** with `n` nodes. Each node is uniquely assigned a value from `1` to `n`. You are also given an integer `startValue` representing the value of the start node `s`, and a different integer `destValue` representing the value of the destination node `t`.
Find the **shortest path** starting from node `s` and ending at node `t`. Generate step-by-step directions of such path as a string consisting of only the **uppercase** letters `'L'`, `'R'`, and `'U'`. Each letter indicates a specific direction:
- `'L'` means to go from a node to its **left child** node.
- `'R'` means to go from a node to its **right child** node.
- `'U'` means to go from a node to its **parent** node.
Return *the step-by-step directions of the **shortest path** from node* `s` *to node* `t`.
**Example 1:**
![https://assets.leetcode.com/uploads/2021/11/15/eg1.png](https://assets.leetcode.com/uploads/2021/11/15/eg1.png)
```
Input: root = [5,1,2,3,null,6,4], startValue = 3, destValue = 6
Output: "UURL"
Explanation: The shortest path is: 3 → 1 → 5 → 2 → 6.
```
**Example 2:**
![https://assets.leetcode.com/uploads/2021/11/15/eg2.png](https://assets.leetcode.com/uploads/2021/11/15/eg2.png)
```
Input: root = [2,1], startValue = 2, destValue = 1
Output: "L"
Explanation: The shortest path is: 2 → 1.
```
**Constraints:**
- The number of nodes in the tree is `n`.
- `2 <= n <= 105`
- `1 <= Node.val <= n`
- All the values in the tree are **unique**.
- `1 <= startValue, destValue <= n`
- `startValue != destValue`
## 题目大意
给你一棵 二叉树 的根节点 root 这棵二叉树总共有 n 个节点。每个节点的值为 1  n 中的一个整数且互不相同。给你一个整数 startValue 表示起点节点 s 的值和另一个不同的整数 destValue 表示终点节点 t 的值。
请找到从节点 s 到节点 t 的 最短路径 ,并以字符串的形式返回每一步的方向。每一步用 大写 字母 'L' 'R' 和 'U' 分别表示一种方向:
- 'L' 表示从一个节点前往它的 左孩子 节点。
- 'R' 表示从一个节点前往它的 右孩子 节点。
- 'U' 表示从一个节点前往它的 父 节点。
请你返回从 s 到 t 最短路径 每一步的方向。
## 解题思路
- 二叉树中一个节点到另一个节点的最短路径一定可以分为两个部分(可能为空):从起点节点向上到两个节点的**最近公共祖先**,再从最近公共祖先向下到达终点节点。
- 首先需要找到起点 s 与公共祖先的节点之间的 path1公共祖先节点与终点 t 的 path2。再删掉 2 个 path 的公共前缀。如果起点 s 和终点 t 在不同的分支上,不存在公共前缀。如果他们在相同的分支上,那么最终答案要去掉这个公共前缀。
- 删除掉公共前缀以后,需要再整理一下最终答案的输出格式。由于题目要求,起点到公共祖先节点需要输出 U所以把这段 path1 全部改成 U然后再拼接上 path2 字符串,即可得到的字符串即为待求 ss 到 tt 每一步的最短路径。
## 代码
```go
package leetcode
import (
"github.com/halfrost/LeetCode-Go/structures"
)
// TreeNode define
type TreeNode = structures.TreeNode
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func getDirections(root *TreeNode, startValue int, destValue int) string {
sPath, dPath := make([]byte, 0), make([]byte, 0)
findPath(root, startValue, &sPath)
findPath(root, destValue, &dPath)
size, i := min(len(sPath), len(dPath)), 0
for i < size {
if sPath[len(sPath)-1-i] == dPath[len(dPath)-1-i] {
i++
} else {
break
}
}
sPath = sPath[:len(sPath)-i]
replace(sPath)
dPath = dPath[:len(dPath)-i]
reverse(dPath)
sPath = append(sPath, dPath...)
return string(sPath)
}
func findPath(root *TreeNode, value int, path *[]byte) bool {
if root.Val == value {
return true
}
if root.Left != nil && findPath(root.Left, value, path) {
*path = append(*path, 'L')
return true
}
if root.Right != nil && findPath(root.Right, value, path) {
*path = append(*path, 'R')
return true
}
return false
}
func reverse(path []byte) {
left, right := 0, len(path)-1
for left < right {
path[left], path[right] = path[right], path[left]
left++
right--
}
}
func replace(path []byte) {
for i := 0; i < len(path); i++ {
path[i] = 'U'
}
}
func min(i, j int) int {
if i < j {
return i
}
return j
}
```