【代码随想录】Day 17 二叉树进阶Ⅱ(平衡、路径、左叶子和)

第一题:

力扣

思路是求左子树和右子树的高度差,用后序遍历,递归三部曲中前两个都能弄清楚,但是最后的单层递归逻辑没弄明白,所以没能AC,以下是看了视频后自己写的:

class Solution {
public:
    int getHight(TreeNode* node) {
        if (node == nullptr) return 0;
        int left = getHight(node->left);
        if (left == -1) return -1; //如果左子树已经不平衡,返回-1
        int right = getHight(node->right);
        if (right == -1) return -1; //如果右子树已经不平衡,返回-1
        if (abs(left - right) > 1) return -1; //判断左右子树是否平衡
        else return 1 + max(left, right); //平衡的话返回高度
    }

    bool isBalanced(TreeNode* root) {
        int result = getHight(root);
        if (result < 0) return false;
        else return true;
    }
};

第二题:

力扣

 大概思路是正确的,使用前序遍历,在走到叶子节点的时候往上返回一个(回溯)。就是string转换的细节以及输出上要注意,节点值与节点值之间要用“->"连接起来:

class Solution {
public:
    void getvalue(TreeNode* node, string path, vector<string>& paths) {
        if (node == nullptr) return;

        path += to_string(node->val);

        if (node->left == nullptr && node->right == nullptr) {
            paths.push_back(path);
        }
        else {
            path += "->";
            getvalue(node->left, path, paths);
            getvalue(node->right, path, paths);
        }
    }

    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> paths;
        getvalue(root, "", paths);
        return paths; 
    }
};

按照回溯思路写的,注意path是vector<int>类型,才可以用&,如果是string&,那么每次pop只能pop掉一个char类型的数字,是不正确的(节点的val可能是十位、百位): 

class Solution {
public:
    void getpath(TreeNode* node, vector<int>& path, vector<string>& paths) {
        path.push_back(node->val);
        if (node->left == nullptr && node->right == nullptr) {
            string res;
            for (auto it = path.begin(); it != path.end()-1; it++) {
                    res += to_string(*it) + "->"; 
            }
            res += to_string(path.back());
            paths.push_back(res);
            return;
        }
        if (node->left) {
            getpath(node->left, path, paths);
            path.pop_back(); //因为path是引用,一直在修改,因此这里要pop掉最后加入的内容,这就是回溯
        }
        if (node->right) {
            getpath(node->right, path, paths);
            path.pop_back();
        }
    }

    vector<string> binaryTreePaths(TreeNode* root) {
        vector<int> path;
        vector<string> paths;
        if (root == NULL) return paths;
        getpath(root, path, paths);
        return paths;
    }
};

如果简化,就是在传参的时候不用引用,这样每次传进去的就是从根节点到父节点的路径,每次子节点的操作不会修改path,如此也就不用再弹出path.back(),此外因为一开始没有写if (node == null) return; 所以需要加上左右子树是否存在的判断:

class Solution {
public:
    void getpath(TreeNode* node, vector<int> path, vector<string>& paths) {
        path.push_back(node->val);
        if (node->left == nullptr && node->right == nullptr) {
            string res;
            for (auto it = path.begin(); it != path.end()-1; it++) {
                    res += to_string(*it) + "->"; 
            }
            res += to_string(path.back());
            paths.push_back(res);
            return;
        }
        if (node->left) {
            getpath(node->left, path, paths);
        }
        if (node->right) {
            getpath(node->right, path, paths);
        }
    }

    vector<string> binaryTreePaths(TreeNode* root) {
        vector<int> path;
        vector<string> paths;
        if (root == NULL) return paths;
        getpath(root, path, paths);
        return paths;
    }
};

 代码随想录的简化版,回溯隐藏在traversal(cur->left, path + "->", result);中的 path + "->" 每次函数调用完,path依然是没有加上"->" 的,这就是回溯:

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;

    }
};

TIPS:回溯要和递归永远在一起!同在一个花括号里,一个递归对应一个回溯!

第三题:

力扣

 已AC,递归法,终止条件为当节点不为左叶子节点时,返回。区分是不是左叶子节点,在递归调用的时候增加一个flag就行,flag会向下传递来源信息,1为向左,-1为向右,只有满足向左走且为叶子节点,才会累加进结果并返回:

class Solution {
public:
    void getValue(TreeNode* node, int& res, int flag) {
        if (node->left == nullptr && node->right == nullptr && flag == 1) {
            res += node->val;
            return;
        }
        if (node->left) getValue(node->left, res, 1);
        if (node->right) getValue(node->right, res, -1);
        return;
    }
    int sumOfLeftLeaves(TreeNode* root) { 
        if (root == nullptr) return 0;
        int res = 0;
        getValue(root, res, 0);
        return res;
    }
};

代码随想录的解法之前也想到过,但是觉得有点麻烦就没写,他是判断的父节点的左孩子是否是叶子节点,如果是就返回左孩子的val,然后左子树求得的值和右子树求得的值累加:

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;
        if (root->left == NULL && root->right== NULL) return 0;

        int leftValue = sumOfLeftLeaves(root->left);    // 左
        if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
            leftValue = root->left->val;
        }
        int rightValue = sumOfLeftLeaves(root->right);  // 右

        int sum = leftValue + rightValue;               // 中
        return sum;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值