【题解】小U的最大连续移动次数问题 | 豆包MarsCode AI刷题

425 阅读3分钟

问题描述

小U决定在一个 m×nm \times n 的地图上行走。地图中的每个位置都有一个高度,表示地形的高低。小U只能在满足以下条件的情况下移动:

  1. 只能上坡或者下坡,不能走到高度相同的点。
  2. 移动时必须交替进行:上坡后必须下坡,下坡后必须上坡,不能连续上坡或下坡。
  3. 每个位置只能经过一次,不能重复行走。

任务是帮助小U找到他在地图上可以移动的最大次数,即在符合所有条件的前提下,小U能走过的最大连续位置数量。

问题分析

读题时

问题的核心是路径搜索,显然可以用 DFS。每次从一个点出发,尝试四个方向移动,对于每个移动,需要判断高度变化是否满足上/下坡交替的条件,同时确保每个点只能访问一次。每次递归返回前需要回溯,将当前点重新标记为未访问状态。为了找到全地图的最长路径,需要从每个点分别尝试作为起点进行搜索,并记录最长路径。每个点最多被递归访问一次,地图大小为 m×nm \times n,加上每个点的四个方向的尝试,总体复杂度约为 O(4×m×n)O(4 \times m \times n),可以接受。

解题时

方向

我采用了 directions 数组存放四对 Pair ,每个 Pair 包含两个整数,分别表示当前点在行和列方向上的位移量。

这样设计的好处是,四个方向的位移量可以统一存储在一个数组中,无需为每个方向单独编写逻辑。而且如果未来需要增加其他方向(例如对角线移动),只需要在 directions 中添加新的位移即可,无需修改核心逻辑。

这种方向数组是路径搜索问题中非常经典的技巧,适用于各种棋盘类或网格类问题,能让代码干净很多。实际使用时,只需要遍历该方向数组,在循环内实现dfs即可,很方便。

上下坡检查

因为要求上下坡交替,所以我为 dfs 函数加了一个up参数,每次递归调用时传入反值,这样就较为方便地解决了,避免了上下坡情况分开时的重复逻辑。同时,判断部分的代码逻辑也就很清晰了,上/坡时判断下一步高度是否高/低于当前位置即可。

代码分析及注释

#include <bits/stdc++.h>

using namespace std;

int solution(int m, int n, vector<vector<int>> &a) {
  vector<vector<bool>> visited(m, vector<bool>(n, false));

  function<int(int, int, bool)> dfs = [&](int x, int y, bool up) -> int {
    int max_path = 0;
    // 方向数组
    vector<pair<int, int>> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    
    // 标记当前位置已访问
    visited[x][y] = true;
    
    // 尝试向四个方向移动
    for (auto& dir : directions) {
      int next_x = x + dir.first;
      int next_y = y + dir.second;

      // 检查是否到边界,是否已访问
      if (next_x >= 0 && next_x < m && next_y >= 0 && next_y < n &&
          !visited[next_x][next_y]) {
        // 检查是否满足上/下坡条件
        if ((up && a[next_x][next_y] < a[x][y]) ||
            (!up && a[next_x][next_y] > a[x][y])) {
          max_path = max(max_path, dfs(next_x, next_y, !up));
        }
      }
    }

    // 回溯,清除标记
    visited[x][y] = false;

    return max_path + 1;
  };

  int max_step = 0;

  // DFS
  for (int i = 0; i < m; ++i) {
    for (int j = 0; j < n; ++j) {
      max_step = max(max_step, dfs(i, j, true));
      max_step = max(max_step, dfs(i, j, false));
    }
  }

  return max_step - 1;
}

int main() {
  // 测试用例,此处省略
  return 0;
}

总结

该题是一道比较常规的搜索问题。如何把上下坡交替结合进递归操作,这个思维点虽然不难,但也算该题的重点之一,如果对递归不够了解的话可能不容易马上想到。