Skip to content

Commit af41c91

Browse files
committed
Add solution 1631、1691
1 parent c7862ae commit af41c91

24 files changed

+903
-76
lines changed

README.md

Lines changed: 56 additions & 56 deletions
Large diffs are not rendered by default.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package leetcode
2+
3+
import (
4+
"sort"
5+
6+
"github.com/halfrost/LeetCode-Go/template"
7+
)
8+
9+
var dir = [4][2]int{
10+
{0, 1},
11+
{1, 0},
12+
{0, -1},
13+
{-1, 0},
14+
}
15+
16+
// 解法一 DFS + 二分
17+
func minimumEffortPath(heights [][]int) int {
18+
n, m := len(heights), len(heights[0])
19+
visited := make([][]bool, n)
20+
for i := range visited {
21+
visited[i] = make([]bool, m)
22+
}
23+
low, high := 0, 1000000
24+
for low < high {
25+
threshold := low + (high-low)>>1
26+
if !hasPath(heights, visited, 0, 0, threshold) {
27+
low = threshold + 1
28+
} else {
29+
high = threshold
30+
}
31+
for i := range visited {
32+
for j := range visited[i] {
33+
visited[i][j] = false
34+
}
35+
}
36+
}
37+
return low
38+
}
39+
40+
func hasPath(heights [][]int, visited [][]bool, i, j, threshold int) bool {
41+
n, m := len(heights), len(heights[0])
42+
if i == n-1 && j == m-1 {
43+
return true
44+
}
45+
visited[i][j] = true
46+
res := false
47+
for _, d := range dir {
48+
ni, nj := i+d[0], j+d[1]
49+
if ni < 0 || ni >= n || nj < 0 || nj >= m || visited[ni][nj] || res {
50+
continue
51+
}
52+
diff := abs(heights[i][j] - heights[ni][nj])
53+
if diff <= threshold && hasPath(heights, visited, ni, nj, threshold) {
54+
res = true
55+
}
56+
}
57+
return res
58+
}
59+
60+
func abs(a int) int {
61+
if a < 0 {
62+
a = -a
63+
}
64+
return a
65+
}
66+
67+
func min(a, b int) int {
68+
if a < b {
69+
return a
70+
}
71+
return b
72+
}
73+
74+
func max(a, b int) int {
75+
if a < b {
76+
return b
77+
}
78+
return a
79+
}
80+
81+
// 解法二 并查集
82+
func minimumEffortPath1(heights [][]int) int {
83+
n, m, edges, uf := len(heights), len(heights[0]), []edge{}, template.UnionFind{}
84+
uf.Init(n * m)
85+
for i, row := range heights {
86+
for j, h := range row {
87+
id := i*m + j
88+
if i > 0 {
89+
edges = append(edges, edge{id - m, id, abs(h - heights[i-1][j])})
90+
}
91+
if j > 0 {
92+
edges = append(edges, edge{id - 1, id, abs(h - heights[i][j-1])})
93+
}
94+
}
95+
}
96+
sort.Slice(edges, func(i, j int) bool { return edges[i].diff < edges[j].diff })
97+
for _, e := range edges {
98+
uf.Union(e.v, e.w)
99+
if uf.Find(0) == uf.Find(n*m-1) {
100+
return e.diff
101+
}
102+
}
103+
return 0
104+
}
105+
106+
type edge struct {
107+
v, w, diff int
108+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package leetcode
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
type question1631 struct {
9+
para1631
10+
ans1631
11+
}
12+
13+
// para 是参数
14+
// one 代表第一个参数
15+
type para1631 struct {
16+
heights [][]int
17+
}
18+
19+
// ans 是答案
20+
// one 代表第一个答案
21+
type ans1631 struct {
22+
one int
23+
}
24+
25+
func Test_Problem1631(t *testing.T) {
26+
27+
qs := []question1631{
28+
29+
{
30+
para1631{[][]int{{1, 2, 2}, {3, 8, 2}, {5, 3, 5}}},
31+
ans1631{2},
32+
},
33+
34+
{
35+
para1631{[][]int{{1, 2, 3}, {3, 8, 4}, {5, 3, 5}}},
36+
ans1631{1},
37+
},
38+
39+
{
40+
para1631{[][]int{{1, 2, 1, 1, 1}, {1, 2, 1, 2, 1}, {1, 2, 1, 2, 1}, {1, 2, 1, 2, 1}, {1, 1, 1, 2, 1}}},
41+
ans1631{0},
42+
},
43+
}
44+
45+
fmt.Printf("------------------------Leetcode Problem 1631------------------------\n")
46+
47+
for _, q := range qs {
48+
_, p := q.ans1631, q.para1631
49+
fmt.Printf("【input】:%v 【output】:%v \n", p, minimumEffortPath(p.heights))
50+
}
51+
fmt.Printf("\n\n\n")
52+
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# [1631. Path With Minimum Effort](https://leetcode.com/problems/path-with-minimum-effort/)
2+
3+
## 题目
4+
5+
You are a hiker preparing for an upcoming hike. You are given `heights`, a 2D array of size `rows x columns`, where `heights[row][col]` represents the height of cell `(row, col)`. You are situated in the top-left cell, `(0, 0)`, and you hope to travel to the bottom-right cell, `(rows-1, columns-1)` (i.e., **0-indexed**). You can move **up****down****left**, or **right**, and you wish to find a route that requires the minimum **effort**.
6+
7+
A route's **effort** is the **maximum absolute difference** in heights between two consecutive cells of the route.
8+
9+
Return *the minimum **effort** required to travel from the top-left cell to the bottom-right cell.*
10+
11+
**Example 1:**
12+
13+
![https://assets.leetcode.com/uploads/2020/10/04/ex1.png](https://assets.leetcode.com/uploads/2020/10/04/ex1.png)
14+
15+
```
16+
Input: heights = [[1,2,2],[3,8,2],[5,3,5]]
17+
Output: 2
18+
Explanation: The route of [1,3,5,3,5] has a maximum absolute difference of 2 in consecutive cells.
19+
This is better than the route of [1,2,2,2,5], where the maximum absolute difference is 3.
20+
```
21+
22+
**Example 2:**
23+
24+
![https://assets.leetcode.com/uploads/2020/10/04/ex2.png](https://assets.leetcode.com/uploads/2020/10/04/ex2.png)
25+
26+
```
27+
Input: heights = [[1,2,3],[3,8,4],[5,3,5]]
28+
Output: 1
29+
Explanation: The route of [1,2,3,4,5] has a maximum absolute difference of 1 in consecutive cells, which is better than route [1,3,5,3,5].
30+
```
31+
32+
**Example 3:**
33+
34+
![https://assets.leetcode.com/uploads/2020/10/04/ex3.png](https://assets.leetcode.com/uploads/2020/10/04/ex3.png)
35+
36+
```
37+
Input: heights = [[1,2,1,1,1],[1,2,1,2,1],[1,2,1,2,1],[1,2,1,2,1],[1,1,1,2,1]]
38+
Output: 0
39+
Explanation: This route does not require any effort.
40+
```
41+
42+
**Constraints:**
43+
44+
- `rows == heights.length`
45+
- `columns == heights[i].length`
46+
- `1 <= rows, columns <= 100`
47+
- `1 <= heights[i][j] <= 10^6`
48+
49+
## 题目大意
50+
51+
你准备参加一场远足活动。给你一个二维 `rows x columns` 的地图 `heights` ,其中 `heights[row][col]` 表示格子 `(row, col)` 的高度。一开始你在最左上角的格子 `(0, 0)` ,且你希望去最右下角的格子 `(rows-1, columns-1)` (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。请你返回从左上角走到右下角的最小 体力消耗值 。
52+
53+
## 解题思路
54+
55+
- 此题和第 778 题解题思路完全一致。在第 778 题中求的是最短连通时间。此题求的是连通路径下的最小体力值。都是求的最小值,只是 2 个值的意义不同罢了。
56+
- 按照第 778 题的思路,本题也有多种解法。第一种解法是 DFS + 二分。先将题目变换一个等价问法。题目要求找到最小体力消耗值,也相当于问是否存在一个体力消耗值 x,只要大于等于 x,一定能连通。利用二分搜索来找到这个临界值。体力消耗值是有序的,此处满足二分搜索的条件。题目给定柱子高度是 [1,10^6],所以体力值一定在 [0,10^6-1] 这个区间内。判断是否取中值的条件是用 DFS 或者 BFS 搜索 (0,0) 点和 (N-1, N-1) 点之间是否连通。时间复杂度:O(mnlogC),其中 m 和 n 分别是地图的行数和列数,C 是格子的最大高度。C 最大为 10^6,所以 logC 常数也很小。空间复杂度 O(mn)。
57+
- 第二种解法是并查集。将图中所有边按照权值从小到大进行排序,并依次加入并查集中。直到加入一条权值为 x 的边以后,左上角到右下角连通了。最小体力消耗值也就找到了。注意加入边的时候,只加入 `i-1``i``j-1``j` 这 2 类相邻的边。因为最小体力消耗意味着不走回头路。上下左右四个方向到达一个节点,只可能从上边和左边走过来。从下边和右边走过来肯定是浪费体力了。时间复杂度:O(mnlog(mn)),其中 m 和 n 分别是地图的行数和列数,图中的边数为 O(mn)。空间复杂度 O(mn),即为存储所有边以及并查集需要的空间。
58+
59+
## 代码
60+
61+
```go
62+
package leetcode
63+
64+
import (
65+
"sort"
66+
67+
"github.com/halfrost/LeetCode-Go/template"
68+
)
69+
70+
var dir = [4][2]int{
71+
{0, 1},
72+
{1, 0},
73+
{0, -1},
74+
{-1, 0},
75+
}
76+
77+
// 解法一 DFS + 二分
78+
func minimumEffortPath(heights [][]int) int {
79+
n, m := len(heights), len(heights[0])
80+
visited := make([][]bool, n)
81+
for i := range visited {
82+
visited[i] = make([]bool, m)
83+
}
84+
low, high := 0, 1000000
85+
for low < high {
86+
threshold := low + (high-low)>>1
87+
if !hasPath(heights, visited, 0, 0, threshold) {
88+
low = threshold + 1
89+
} else {
90+
high = threshold
91+
}
92+
for i := range visited {
93+
for j := range visited[i] {
94+
visited[i][j] = false
95+
}
96+
}
97+
}
98+
return low
99+
}
100+
101+
func hasPath(heights [][]int, visited [][]bool, i, j, threshold int) bool {
102+
n, m := len(heights), len(heights[0])
103+
if i == n-1 && j == m-1 {
104+
return true
105+
}
106+
visited[i][j] = true
107+
res := false
108+
for _, d := range dir {
109+
ni, nj := i+d[0], j+d[1]
110+
if ni < 0 || ni >= n || nj < 0 || nj >= m || visited[ni][nj] || res {
111+
continue
112+
}
113+
diff := abs(heights[i][j] - heights[ni][nj])
114+
if diff <= threshold && hasPath(heights, visited, ni, nj, threshold) {
115+
res = true
116+
}
117+
}
118+
return res
119+
}
120+
121+
func abs(a int) int {
122+
if a < 0 {
123+
a = -a
124+
}
125+
return a
126+
}
127+
128+
func min(a, b int) int {
129+
if a < b {
130+
return a
131+
}
132+
return b
133+
}
134+
135+
func max(a, b int) int {
136+
if a < b {
137+
return b
138+
}
139+
return a
140+
}
141+
142+
// 解法二 并查集
143+
func minimumEffortPath1(heights [][]int) int {
144+
n, m, edges, uf := len(heights), len(heights[0]), []edge{}, template.UnionFind{}
145+
uf.Init(n * m)
146+
for i, row := range heights {
147+
for j, h := range row {
148+
id := i*m + j
149+
if i > 0 {
150+
edges = append(edges, edge{id - m, id, abs(h - heights[i-1][j])})
151+
}
152+
if j > 0 {
153+
edges = append(edges, edge{id - 1, id, abs(h - heights[i][j-1])})
154+
}
155+
}
156+
}
157+
sort.Slice(edges, func(i, j int) bool { return edges[i].diff < edges[j].diff })
158+
for _, e := range edges {
159+
uf.Union(e.v, e.w)
160+
if uf.Find(0) == uf.Find(n*m-1) {
161+
return e.diff
162+
}
163+
}
164+
return 0
165+
}
166+
167+
type edge struct {
168+
v, w, diff int
169+
}
170+
```
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package leetcode
2+
3+
import "sort"
4+
5+
func maxHeight(cuboids [][]int) int {
6+
n := len(cuboids)
7+
for i := 0; i < n; i++ {
8+
sort.Ints(cuboids[i]) // 立方体三边内部排序
9+
}
10+
// 立方体排序,先按最短边,再到最长边
11+
sort.Slice(cuboids, func(i, j int) bool {
12+
if cuboids[i][0] != cuboids[j][0] {
13+
return cuboids[i][0] < cuboids[j][0]
14+
}
15+
if cuboids[i][1] != cuboids[j][1] {
16+
return cuboids[i][1] < cuboids[j][1]
17+
}
18+
return cuboids[i][2] < cuboids[j][2]
19+
})
20+
res := 0
21+
dp := make([]int, n)
22+
for i := 0; i < n; i++ {
23+
dp[i] = cuboids[i][2]
24+
res = max(res, dp[i])
25+
}
26+
for i := 1; i < n; i++ {
27+
for j := 0; j < i; j++ {
28+
if cuboids[j][0] <= cuboids[i][0] && cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2] {
29+
dp[i] = max(dp[i], dp[j]+cuboids[i][2])
30+
}
31+
}
32+
res = max(res, dp[i])
33+
}
34+
return res
35+
}
36+
37+
func max(x, y int) int {
38+
if x > y {
39+
return x
40+
}
41+
return y
42+
}

0 commit comments

Comments
 (0)