算法题解:用DFS(递归)寻找树中的最大权值路径

题目分析

题目链接:124. Binary Tree Maximum Path Sum

不难分析出,最大的路径是“^型”的,从一个最高点向下延伸的两条路径组成一个“^型”路径。注意这个“最高点”不一定是树的根。
并且,这两条路径必定分别经过左右子节点,并且是向下路径中权值最大的。
由于每个节点都有可能是“最高点”,因此对于每个节点(可以用DFS/BFS遍历每个节点),我们都要计算出以该节点为“最高点”的最大“^型”路径;。为了计算出该值,我们要先得到经过左子节点的最长向下路径经过右子节点的最长向下路径(这两个值可以用DFS得到),两者相加,再加上该节点本身的权值,就得到了以该节点为“最高点”的最大“^型”路径;

这时如果不注意可能会出现严重的性能问题:两层DFS嵌套。第一层DFS用于遍历每个节点,并假设这个节点为“^型”路径的最高点;对于每个节点,又会进行第二层DFS:用于计算两个最长的向下路径。
两层DFS嵌套会大大影响计算时间,我们应该合并两次DFS。注意到DFS只不过是一种特殊的递归调用,对于父节点的每个子节点,都进行一次递归调用,每个子节点都遍历完毕(子节点的调用堆栈经历装载、弹出)以后,返回到父节点的调用堆栈(如果父节点不需要进行后续的计算,则父节点的调用堆栈弹出)。我们如果在第一次遍历中就计算出经过子节点的最长的向下路径,并返回给父节点的调用堆栈,父节点就能直接计算出经过左/右子节点的最长的向下路径,从而避免第二层的递归调用。

代码实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution
{
  private:
    // 存放已经找到的最大路径权值
    int result;

  public:
    int maxPathSum(TreeNode *root)
    {
        this->result = INT_MIN;
        calculateMaxPathDown(root);
        return this->result;
    }

    // 计算从subRoot向下的最大路径权值
    // 如果经过subRoot的路径都为负值,则返回0(终止于subRoot的路径权值)
    int calculateMaxPathDown(TreeNode *subRoot)
    {
        if (subRoot == NULL)
            return 0;
        int leftMaxPathDown = calculateMaxPathDown(subRoot->left);
        int rightMaxPathDown = calculateMaxPathDown(subRoot->right);

        // 这个语句与本函数的目的无关,但对于得到最终结果至关重要
        // 计算以subRoot为最高点的最大 “^型” 路径,将它与已经找到的最大路径比较
        this->result = max(leftMaxPathDown + rightMaxPathDown + subRoot->val, this->result);

        // 返回从subRoot向下的最大路径权值
        return max(0, max(leftMaxPathDown, rightMaxPathDown) + subRoot->val);
    }
};

由于对每个节点仅仅进行一次递归调用,因此时间复杂度为O(n)

由此可见,在选择递归之前,我们应该仔细思考每次递归调用应该计算什么、返回什么。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!对于扫雷游戏的题解,我可以给你一些思路和代码示例。首先,你需要了解扫雷游戏的规则和要求。接下来,你可以使用C++语言来实现游戏逻辑和界面。 下面是一个简单的扫雷游戏的C++代码示例: ```cpp #include <iostream> #include <vector> #include <random> using namespace std; class MinesweeperGame { private: int rows; int cols; vector<vector<char>> board; vector<vector<bool>> revealed; vector<pair<int, int>> directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; public: MinesweeperGame(int m, int n, int mineCount) { rows = m; cols = n; board.resize(rows, vector<char>(cols, ' ')); revealed.resize(rows, vector<bool>(cols, false)); placeMines(mineCount); calculateNumbers(); } void printBoard() { cout << " "; for (int j = 0; j < cols; j++) { cout << j << " "; } cout << endl; for (int i = 0; i < rows; i++) { cout << i << " |"; for (int j = 0; j < cols; j++) { cout << board[i][j] << "|"; } cout << endl; } } bool isGameOver() { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (board[i][j] == 'M' && revealed[i][j]) { return true; } } } return false; } void reveal(int row, int col) { if (row < 0 || row >= rows || col < 0 || col >= cols || revealed[row][col]) { return; } revealed[row][col] = true; if (board[row][col] == 'M') { return; } if (board[row][col] == '0') { for (auto dir : directions) { reveal(row + dir.first, col + dir.second); } } } private: void placeMines(int mineCount) { random_device rd; mt1

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值