【算法学习计划】回溯 -- 二叉树中的深搜

目录

leetcode 2331.计算布尔二叉树的值

leetcode 129.求根节点到叶节点数字之和

leetcode 814.二叉树剪枝

leetcode 98.验证二叉搜索树

leetcode 230.二叉搜索树中第K小的元素

leetcode 257.二叉树的所有路径


今天我们通过 6 道在leedcode上的题目,来学习一下回溯算法中二叉树中的深搜的相关问题

(下文中的标题都是leedcode对应题目的链接)

leetcode 2331.计算布尔二叉树的值

挺简单的一道题,我们遍历一下左子树,然后再遍历一下右子树,接着根据根节点的值,来决定是 || 还是 && 即可

递归出口就是,当这个节点为叶子节点(因为是完全二叉树,所以有子节点就必定有两个,要么就没有),那么我们直接返回他的值即可

代码如下:

class Solution {
public:
    bool evaluateTree(TreeNode* root) 
    {
        if(root->left == nullptr) return root->val;

        bool l = evaluateTree(root->left);
        bool r = evaluateTree(root->right);
        if(root->val == 2) return l || r;
        return l && r; 
    }
};

leetcode 129.求根节点到叶节点数字之和

这道题目,我们直接使用一个变量 n,然后我们每遇到一个节点,我们就将这个节点里面的值加上10倍的n

假设(示例二)我们现在在 9,那么 n 就是4,那么我们往下就传一个49,也就是 n*10 + root->val

当我们碰到根节点的时候,我们直接将加完之后的值返回

上面我们需要用函数来接收,但是因为是值的相加,所以我们直接+=即可

代码如下:

class Solution {
public:
    int dfs(TreeNode* root, int n)
    {
        int ret = 0;
        if(!root->left && !root->right) return n * 10 + root->val;
        if(root->left) ret += dfs(root->left, n * 10 + root->val);
        if(root->right) ret += dfs(root->right, n * 10 + root->val);
        return ret;
    }
    int sumNumbers(TreeNode* root) 
    {
        return dfs(root, 0);    
    }
};

leetcode 814.二叉树剪枝

面对这道题目,我们直接抓着根节点就可以了

想象一下,我们先递归一下左,然后拿左链接递归后的结果(因为有可能左边直接变成空了)

右子树同理

接着我们遍历完了左和右,接下来我们就看一下根节点

对于根节点而言,如果左边是空,右边也是空,那就意味着左右都被剪掉了,那么如果这时根节点也是 0 的话,那么直接将根节点变成 nullptr 即可,然后不管怎么样,我们都返回根节点(根节点不一定会变成空)

代码如下:

class Solution {
public:
    TreeNode* dfs(TreeNode* root)
    {
        if(!root) return nullptr;
        root->left = dfs(root->left);
        root->right = dfs(root->right);

        if(!root->left && !root->right && root->val == 0)
            root = nullptr;
        return root;
    }
    TreeNode* pruneTree(TreeNode* root) 
    {
        return dfs(root);   
    }
};

leetcode 98.验证二叉搜索树

想要解决这道题目超级简单,因为二叉搜索树有一个特点就是,中序遍历的时候一定是有序且从小到大的

所以我们就有了一下两种解题思路,第一个是,我们直接创建一个全局的数组,我们再中序遍历二叉树,然后每遍历到一个节点,我们就放一个数到数组里面,最后我们再遍历一下数组,看看是不是升序即可

解法一代码就不写了,很简单可以自己尝试

解法二就是在遍历的时候比较

我们准备俩全局变量,一个表示是否是升序(flag),一个表示要比较的前一个数(pre)

然后我们创建pre的时候,赋值一个INT_MIN给他,那么后面数字一定比他大

最后边遍历边比较,只要不是升序,就改变flag,最后返回flag即可

代码如下:

class Solution {
public:
    long pre = LONG_MIN;
    bool isValidBST(TreeNode* root) 
    {
        if(!root) return true;
        bool l = isValidBST(root->left);
        if(root->val > pre)
            pre = root->val;
        else return false;

        bool r = isValidBST(root->right);

        return l && r;;
    }
};

leetcode 230.二叉搜索树中第K小的元素

这一道题和上一道题目一样,其实也是有两种很容易想出来的做法

首先第一个(比较简单就不写代码了,只讲思路),我们可以直接用一个小根堆,我们遍历一个数就往里面放一个数,遍历完一遍之后,我们直接对这个堆 pop  K-1 次即可,最后我们的堆顶就是我们想要的答案

第二种解法就是,我们还是中序遍历,因为这是一个二叉搜索树

我们在全局定义一个变量 time,让这个变量的值和 K 相同,我们每遍历一个元素,我们就将这个time--,当time减小到 0 的时候,我们当前递归到的元素就是我们要的答案,但是我们还要将这个数带出去,所以我们还可以再搞一个全局变量ret,当time为 0 的时候,我们就将那个元素放进ret里面,最后我们再返回这个ret即可

代码如下:

class Solution {
public:
    int time;
    int ret;
    void dfs(TreeNode* root)
    {
        if(!root) return;
        dfs(root->left);

        if(!(--time))
        {
            ret = root->val;
            return;
        }
        
        dfs(root->right);

    }
    int kthSmallest(TreeNode* root, int k) 
    {
        time = k;
        dfs(root);
        return ret;
    }
};

leetcode 257.二叉树的所有路径

这个也不难,核心思想就是,先在全局创建一个vector<string>,我们将当前的值和 -> 一个一个传下去,当我们遍历到叶子节点的时候,我们就直接将这个string放进全局vector里面就好了

代码如下:

class Solution {
public:
    vector<string> ret;
    void dfs(TreeNode* root, string load)
    {
        if(!root->left && !root->right)
        {
            ret.push_back(load + to_string(root->val));
            return;
        }
        load = load + to_string(root->val) + "->";
        if(root->left) dfs(root->left, load);
        if(root->right) dfs(root->right, load);
    }
    vector<string> binaryTreePaths(TreeNode* root) 
    {
        dfs(root, "");
        return ret;
    }
};

这篇文章到这里就结束了

接下来我们还会有更多递归系列的博客,如果觉得对你有帮助的可以关注一下!!~( ̄▽ ̄)~*