代码随想录算法训练营第十八天|513.找树左下角的值、112. 路径总和、113.路径总和ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

13.找树左下角的值

题目链接:13.找树左下角的值

两种方法,递归法和迭代法
递归法:记录深度,不断递归,当到达最底层最左边叶子节点时,返回值
迭代法:使用层序遍历方法,用一个变量不断记录每一层最左边的值,当到达最后一层时,即为所求。

1.递归法

class Solution {
public:
    int maxDepth = INT_MIN;
    int result;
    void traversal(TreeNode* node, int depth) {
        if (node->left == nullptr && node->right == nullptr) {
            if (depth > maxDepth) {
                maxDepth = depth;
                result = node->val;
            }
        }

        if (node->left) {
            depth++;
            traversal(node->left, depth);
            depth--; //回溯

            //代码可精简为如下
            //traversal(node->left, depth + 1);
        }
        if (node->right) {
            depth++;
            traversal(node->right, depth);
            depth--;
        }
    }
    int findBottomLeftValue(TreeNode* root) {
        traversal(root, 0);
        return result;
    }
};

2.迭代法

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        que.push(root);
        int result = 0;
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (i == 0) result = node->val; //记录每层最左边值
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return result;
    }
};

112. 路径总和

题目链接:112. 路径总和

递归法, 中止条件为到达叶子节点且恰好和为目标值,返回true,反之返回false;

如果左右节点递归时,返回的为true,就不断向上层返回true,注意回溯过程。

可以用targetnum不断减当前节点的值代替不断求和使代码更简洁。

class Solution {
public:
    bool travesal(TreeNode* node, int target) {
        if (node->left == nullptr && node->right == nullptr && target == 0) {
            return true;
        }
        if (!node->left && !node->right) return false;

        if (node->left) {
            target -= node->left->val;
            if (travesal(node->left, target)) return true;
            target += node->left->val;
        }
        if (node->right) {
            target -= node->right->val;
            if (travesal(node->right, target)) return true;
            target += node->right->val;
        }
        return false;

    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) return false;
        return travesal(root, targetSum - root->val);
    }
};

113.路径总和ii

题目链接:113.路径总和ii

此题和上题一样,只不过是记录满足条件的路径。
路径记录可参考257. 二叉树的所有路径

class Solution {
public:
    void traversal(TreeNode* node, vector<int>& path, int count, vector<vector<int>> &result) {
        path.push_back(node->val);
        if (!node->left && !node->right && count == 0) {
            result.push_back(path);
            return;
        }
        
        if (node->left) {
            traversal(node->left, path, count - node->left->val,result);
            path.pop_back(); //回溯
        }
        if (node->right) {
            traversal(node->right, path, count - node->right->val,result);
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<int> path;
        vector<vector<int>> result;
        if (root == nullptr) return result;
        traversal(root, path, targetSum - root->val, result);
        return result;
    }
};

106.从中序与后序遍历序列构造二叉树

题目链接:106.从中序与后序遍历序列构造二叉树

后序遍历的最后一个数是根的值,然后利用根的值在中序遍历中将中序遍历划分为左中序和右中序,然后在后序遍历中将除去最后一个元素的数组划分为左后序和右后序。

注意划分数组的方法

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        //数组为空,二叉树为空
        if (postorder.size() == 0) return nullptr;

        int rootvalue = postorder[postorder.size()-1];
        TreeNode* root = new TreeNode(rootvalue);
        if (postorder.size() == 1) return root;
        int index = 0; //在循环外构建变量
        for (; index < inorder.size(); index++) {
            if (inorder[index] == rootvalue) break;
        }
        //注意坚持左闭右开
        vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
        vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
        /*
        for (int i = 0; i < inorder.size(); i++) {
            if (i < index) {
                leftInorder.push_back(inorder[i]);
            } else if (i > index) {
                rightInorder.push_back(inorder[i]);
            }
        } 
        */
        vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
        vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end() - 1);
        /*
        for (int i = 0; i < postorder.size() - 1; i++) {
            if (i < leftInorder.size()) {
                leftPostorder.push_back(postorder[i]);
            } else {
                rightPostorder.push_back(postorder[i]);
            }
        }
        */
        root->left = buildTree(leftInorder, leftPostorder);
        root->right = buildTree(rightInorder, rightPostorder);
        return root;
    }
};

105.从前序与中序遍历序列构造二叉树

题目链接:105.从前序与中序遍历序列构造二叉树
此题和前一题相同,先用前序遍历第一个数确定根节点,然后再划分。

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (preorder.size() == 0) return nullptr;

        int rootvalue = preorder[0];
        TreeNode* root = new TreeNode(rootvalue);
        if (preorder.size() == 1) return root;
        int index = 0;
        for (;index < inorder.size(); index++) {
            if (inorder[index] == rootvalue) break;
        }

        vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
        vector<int> rightInorder(inorder.begin() + index + 1, inorder.end()); //注意前序去掉第一个数
        vector<int> leftPreorder(preorder.begin() + 1, preorder.begin() + 1 +leftInorder.size());
        vector<int> rightPreorder(preorder.begin() + 1 + leftInorder.size(), preorder.end());
        root->left = buildTree(leftPreorder, leftInorder);
        root->right = buildTree(rightPreorder, rightInorder);
        return root;
    }
};

总结

  • 注意回溯的处理
  • 前序和后序数组不能确定二叉树
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值