一、Problem
你被请来给一个要举办高尔夫比赛的树林砍树. 树林由一个非负的二维数组表示, 在这个数组中:
- 0 表示障碍,无法触碰到.
- 1 表示可以行走的地面.
- 比 1 大的数 表示一颗允许走过的树的高度.
每一步,你都可以向上、下、左、右四个方向之一移动一个单位,如果你站的地方有一棵树,那么你可以决定是否要砍倒它。
你被要求按照树的高度从低向高砍掉所有的树,每砍过一颗树,树的高度变为 1
你将从(0,0)点开始工作,你应该返回你砍完所有树需要走的最小步数。 如果你无法砍完所有的树,返回 -1 。
可以保证的是,没有两棵树的高度是相同的,并且你至少需要砍倒一棵树。
输入:
[
[2,3,5],
[0,0,4],
[8,7,6]
]
输出: 8
解释: (0,0) 位置的树,你可以直接砍去,不用算步数
提示:
1 <= forest.length <= 50
1 <= forest[i].length <= 50
0 <= forest[i][j] <= 10^9
二、Solution
方法一:bfs
题意
砍完一个点 (i, j) 的树,寻找下一棵比当前树高度小的树 next,注,关键来了:① next 可能不在 (i, j) 的周围(上下左右),也就是说,你可以砍完树回去再回来也是可以的 🤦♂️
所以,这题不能裸着做
思路
将树的位置、树高先预处理到一个容器中;然后容器按照树高进行排序;最后就是检查初始位置 (0, 0) 能否到达树的每一个位置,到不了就不能砍完树
这样我们就只需要计算所有 “相邻” 的树的距离总和
class Solution {
public:
struct node {int x, y;};
int n, m, d[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };
int cutOffTree(vector<vector<int>>& g) {
n=g.size(), m=g[0].size();
vector<vector<int>> ts;
for (int i=0; i<n; i++)
for (int j=0; j<m; j++) if(g[i][j]) {
ts.push_back({i, j, g[i][j]});
}
sort(ts.begin(), ts.end(), [&] (auto t1, auto t2){
return t1[2] < t2[2];
});
int sx=0, sy=0, ans=0;
for (auto& t : ts) {
int dist = bfs(sx, sy, t[0], t[1], g);
if (dist == -1) return -1;
sx=t[0], sy=t[1], ans += dist;
}
return ans;
}
int bfs(int sx, int sy, int ex, int ey, vector<vector<int>>& g) {
int op=0, vis[n][m];
queue<node> q;
memset(vis, 0, sizeof vis);
q.push({sx, sy}), vis[sx][sy]=1;
while (!q.empty()) {
for (int i=q.size(); i; i--) {
node now = q.front(); q.pop();
if (now.x==ex && now.y==ey) return op;
for (int k=0; k<4; k++) {
int xx=now.x+d[k][0], yy=now.y+d[k][1];
if (xx>=0 && xx<n && yy>=0 && yy<m && !vis[xx][yy] && g[xx][yy]) {
q.push({xx, yy});
vis[xx][yy]=1;
}
}
}
op++;
}
return -1;
}
};
复杂度分析
- 时间复杂度: O ( Q × n m ) O(Q × nm) O(Q×nm),792 ms…
- 空间复杂度: O ( n m ) O(nm) O(nm),
方法二:
复杂度分析
- 时间复杂度: O ( ) O() O(),
- 空间复杂度: O ( ) O() O(),