二叉树:以为使用了递归,其实还隐藏着回溯

Posted 代码随想录

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树:以为使用了递归,其实还隐藏着回溯相关的知识,希望对你有一定的参考价值。

给「代码随想录」一个星标吧!

这是对昨天本周小结篇的补充

昨天的总结篇中,有两处问题需要说明一波。

求相同的树

中求100.相同的树的代码中,我笔误贴出了 求对称树的代码了,细心的同学应该都发现了。

那么如下我再给出求100. 相同的树 的代码,如下:

class Solution {
public:
    bool compare(TreeNode* tree1, TreeNode* tree2) {
        if (tree1 == NULL && tree2 != NULL) return false;
        else if (tree1 != NULL && tree2 == NULL) return false;
        else if (tree1 == NULL && tree2 == NULL) return true;
        else if (tree1->val != tree2->val) return false; // 注意这里我没有使用else

        // 此时就是:左右节点都不为空,且数值相同的情况
        // 此时才做递归,做下一层的判断
        bool compareLeft = compare(tree1->left, tree2->left);       // 左子树:左、 右子树:左
        bool compareRight = compare(tree1->right, tree2->right);    // 左子树:右、 右子树:右
        bool isSame = compareLeft && compareRight;                  // 左子树:中、 右子树:中(逻辑处理)
        return isSame;

    }
    bool isSameTree(TreeNode* p, TreeNode* q) {
        return compare(p, q);
    }
};

以上的代码相对于: 仅仅修改了变量的名字(为了符合判断相同树的语境)和 遍历的顺序。

大家应该会体会到:「认清本质之后, 对称树的代码 稍作修改 就可以直接用来AC 100.相同的树。」

递归中隐藏着回溯

在中我强调了本题其实是用到了回溯的,并且给出了第一个版本的代码,把回溯的过程充分的体现了出来。

如下的代码充分的体现出回溯:(257. 二叉树的所有路径)

class Solution {
private:

    void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
        path.push_back(cur->val);
        // 这才到了叶子节点
        if (cur->left == NULL && cur->right == NULL) {
            string sPath;
            for (int i = 0; i < path.size() - 1; i++) {
                sPath += to_string(path[i]);
                sPath += "->";
            }
            sPath += to_string(path[path.size() - 1]);
            result.push_back(sPath);
            return;
        }
        if (cur->left) {
            traversal(cur->left, path, result);
            path.pop_back(); // 回溯
        }
        if (cur->right) {
            traversal(cur->right, path, result);
            path.pop_back(); // 回溯
        }
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        vector<int> path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;
    }
};

如下为精简之后的递归代码:(257. 二叉树的所有路径) 注意注释

class Solution {
private:
    void traversal(TreeNode* cur, string path, vector<string>& result) {
        path += to_string(cur->val); // 中
        if (cur->left == NULL && cur->right == NULL) {
            result.push_back(path);
            return;
        }
        if (cur->left) traversal(cur->left, path + "->", result); // 左  回溯就隐藏在这里
        if (cur->right) traversal(cur->right, path + "->", result); // 右 回溯就隐藏在这里
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        string path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;
    }
};

上面精简之后的代码,大家貌似感受不到回溯了,其实「回溯就隐藏在traversal(cur->left, path + "->", result);中的 path + "->"。 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。」

为了把这份精简代码的回溯过程展现出来,大家可以试一试吧:

traversal(cur->left, path + "->", result); // 左  回溯就隐藏在这里

改成如下代码:

path += "->";
traversal(cur->left, path, result); // 左

即:


if (cur->left) {
    path += "->";
    traversal(cur->left, path, result); // 左
}
if (cur->right) {
    path += "->";
    traversal(cur->right, path, result); // 右
}

此时就没有回溯了,这个代码就是通过不了的了。

如果想把回溯加上,就要 在上面代码的基础上,加上回溯,就可以AC了。

if (cur->left) {
    path += "->";
    traversal(cur->left, path, result); // 左
    path.pop_back(); // 回溯
    path.pop_back();
}
if (cur->right) {
    path += "->";
    traversal(cur->right, path, result); // 右
    path.pop_back(); // 回溯
    path.pop_back();
}

「大家应该可以感受出来,如果把 path + "->"作为函数参数就是可以的,因为并有没有改变path的数值,执行完递归函数之后,path依然是之前的数值(相当于回溯了)」

如果有点遗忘了,建议把这篇在仔细看一下,然后再看这里的总结,相信会豁然开朗。

这里我尽量把逻辑的每一个细节都抠出来展现了,希望对大家有所帮助!

最近Carl也在出游,都是在路上挤时间写文章,如果哪里有出入,欢迎大家多多纠正哈。

在留言区留下你的思路吧!

-------end-------

我将算法学习相关的资料已经整理到了Github :https://github.com/youngyangyang04/leetcode-master,里面还有leetcode刷题攻略、各个类型经典题目刷题顺序、思维导图看一看一定会有所收获,如果给你有帮助给一个star支持一下吧!

另外因为公众号改版,时间线被打乱,一些精彩文章大家可能错过了。如果感觉这里的文章对你有帮助, 赶紧给「代码随想录」加一个星标吧,方便第一时间阅读文章

往期 精彩回顾



















「代码随想录」期待你的关注!

每天8:35准时推送一道经典算法题目,推送的每道题目都不是孤立的,而是由浅入深,环环相扣,帮你梳理算法知识脉络,轻松学算法!

二叉树:以为使用了递归,其实还隐藏着回溯
刷题可以加我微信!
右边为个人微信,添加时备注:简单自我介绍」+组队题」
我就知道你[在看]


以上是关于二叉树:以为使用了递归,其实还隐藏着回溯的主要内容,如果未能解决你的问题,请参考以下文章

二叉树专题

二叉树遍历(先序中序后序)

LeetCode二叉树#16二叉树的最近公共祖先(递归后序遍历,巩固回溯机制)

大厂面试不可不会的二叉树相关算法

二叉树算法总结

常见递归模式