题目
你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。
一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。请你返回从左上角走到右下角的最小 体力消耗值 。
解题思路
二分查找来确定最小的体力消耗值。首先初始化一个左边界left为0,一个右边界right为1e6(题目中给出的最大高度差)。然后在每次查找过程中,计算出中间值mid,并使用深度优先搜索来判断是否存在一条路径,其中相邻格子之间的高度差绝对值不超过mid。如果存在一条路径,则将right更新为mid,否则将left更新为mid + 1。最终返回left作为最小的体力消耗值。
在深度优先搜索的过程中,我们使用一个visited数组来记录已经访问过的格子,避免重复访问。通过递归的方式,我们可以依次尝试上下左右四个方向的移动,并判断是否满足条件。如果能够到达右下角的格子,则返回true,否则返回false。
代码实现
class Solution {
public:
int minimumEffortPath(vector<vector<int>>& heights) {
int rows = heights.size();
int cols = heights[0].size();
vector<vector<bool>> visited(rows, vector<bool>(cols, false));
int left = 0;
int right = 1e6; // 最大高度差为1e6
while (left < right) {
int mid = left + (right - left) / 2;
if (dfs(heights, visited, 0, 0, mid)) {
right = mid;
} else {
left = mid + 1;
}
// 重置visited数组
visited = vector<vector<bool>>(rows, vector<bool>(cols, false));
}
return left;
}
private:
bool dfs(vector<vector<int>>& heights, vector<vector<bool>>& visited, int row, int col, int maxDiff) {
int rows = heights.size();
int cols = heights[0].size();
if (row == rows - 1 && col == cols - 1) {
return true;
}
visited[row][col] = true;
// 上下左右四个方向
vector<pair<int, int>> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for (const auto& dir : directions) {
int newRow = row + dir.first;
int newCol = col + dir.second;
if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols
&& !visited[newRow][newCol]
&& abs(heights[row][col] - heights[newRow][newCol]) <= maxDiff) {
if (dfs(heights, visited, newRow, newCol, maxDiff)) {
return true;
}
}
}
return false;
}
};