LeetCode | C++ 513.找树左下角的值、112. 路径总和 113.路径总和ii 、 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

52 篇文章 0 订阅

513.找树左下角的值

LeetCode-513-题目链接
深度最大的叶子结点一定是最后一行

对于本题而言,递归方法:使用前序、中序、后序都是可以的

因为本题中是没有中 节点的处理逻辑的,只需要先遍历左就可以;因为优先遍历的是左节点,所以只要我们一旦得到深度最大的节点,我们得到的就是最后一行最靠左侧的结点。

注意:最靠左侧的结点 并不一定是 左孩子

在遍历的时候每当遇到深度 比之前 深度大的结点,就更新最左侧的值

同时本题也可以使用迭代法,也就是使用队列的层序遍历方法,是一种比较容易理解方法。

递归法

class Solution {
public:
    // 使用递归写法
    int depth_ = INT_MIN;
    int result;
    int findBottomLeftValue(TreeNode* root) {   
        traversal(root, 0);
        return result;
    }
    
    void traversal(TreeNode* node, int depth) {
        if (node == NULL) return;
        if (node->left == NULL && node->right == NULL) {
            if (depth_ < depth) {
                depth_ = depth;
                result = node->val;
            }  
            return;
        }
        if (node->left) {
            depth++;
            traversal(node->left, depth);
            depth--;
        }
        if (node->right) {
            depth++;
            traversal(node->right, depth);
            depth--;
        }
        return;
    }
};

迭代法

class Solution {
public:
    // 使用迭代写法  层序遍历 队列
    int findBottomLeftValue(TreeNode* root) {   
        queue<TreeNode*> queue1;
        queue1.push(root);

        int result;
        while(!queue1.empty()) {
            int size;
            size = queue1.size();

            for(int i = 0; i < size; i++) {
                TreeNode* node = queue1.front();
                queue1.pop();
                // 每次只记录 每层的第一个结点的值
                if (i == 0) {
                    result = node->val;
                }
                if (node->left) {
                    queue1.push(node->left);
                }
                if (node->right) {
                    queue1.push(node->right);
                }
            }
        } 
        return result; 
    }
};

112.路径总和

LeetCode-112-题目链接
对于找到一条 符合的路径就返回,就一路 一直返回 true。并不需要遍历整棵树

可以在遍历的时候对总和进行递减,这样代码更简洁

同样,该题对遍历顺序没有要求,因为不涉及中 结点的处理。

  • 112 题 是找到一个就返回
  • 113 题 是找到所有的路径
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == NULL) return false;
        return traversal(root, targetSum - root->val);
    }
    bool traversal(TreeNode* node, int targetSum) {
        if (node->left == NULL && node->right == NULL && targetSum == 0) return true;
        if (node->left == NULL && node->right == NULL && targetSum != 0) return false;
        if (node->left) {
            targetSum -= node->left->val;
            if (traversal(node->left, targetSum)) return true;
            targetSum += node->left->val;
        }
        if (node->right) {
            targetSum -= node->right->val;
            if (traversal(node->right, targetSum)) return true;
            targetSum += node->right->val;
        }
        return false;
    }
};

113.路径总和ii

LeetCode-113-题目链接

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

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

LeetCode-106-题目链接

  • 思路:

  • (1)若后序数组为空,则返回空结点

  • (2)后序数组中的最后一个元素为结点元素

  • (3)寻找中序数组位置作为切割点

  • (4)进行中序数组的切割

  • (5)基于切割后的中序数组,进行后序数组的切割

  • (6)最后递归处理左区间和右区间

  • 只有前序和后序是不能唯一确定一棵二叉树的;中序和后序 以及 中序和前序 都可以,思路是一致的。

  • 本题给出了 便于理解的题解,但是每次递归时定义了新的vector,对空间和时间有很大的消耗,下面给出了,对于数组分割的优化解法:利用vector 下标索引进行处理。对于本方法需要注意的是:需要把之间对vector的操作,全部变成索引之间的关系来表示。

容易理解版本

// 便于理解版本
class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        return traversal(inorder, postorder);
    }

    TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
        if (postorder.size() == 0) return NULL;
        TreeNode* root = new TreeNode(postorder[postorder.size() - 1]);
        if (postorder.size() == 1) return root;

        vector<int> inorderLeft, inorderRight;
        int mid;
        // 寻找中序数组位置作为切割点,同时进行中序数据的切割
        for (int i = 0; i < inorder.size(); i++) {
            if (root->val == inorder[i]) {
                mid = i;
                break;
            }
            inorderLeft.push_back(inorder[i]);
        }
        for (int i = mid + 1; i < inorder.size(); i++) {
            inorderRight.push_back(inorder[i]);
        }
        
        // postorder舍弃末尾元素
        postorder.resize(postorder.size() - 1);
        // 接下来进行后序数组的切割
        // 按照切割后的中序数组的 长度

        vector<int> postorderLeft, postorderRight;
        for (int i = 0; i < inorderLeft.size(); i++) {
            postorderLeft.push_back(postorder[i]);
        }
        for (int i = inorderLeft.size(); i < postorder.size(); i++) {
            postorderRight.push_back(postorder[i]);
        }

        root->left = traversal(inorderLeft, postorderLeft);
        root->right = traversal(inorderRight, postorderRight);
        return root;
    }
};

使用vector下标索引优化版本

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }

    TreeNode* traversal(vector<int>& inorder, int inorderBegin, int inorderEnd,  vector<int>& postorder, int postorderBegin, int postorderEnd) {
        if (postorderBegin == postorderEnd) return NULL;
        TreeNode* root = new TreeNode(postorder[postorderEnd - 1]);
        if ((postorderEnd - postorderBegin) == 1) return root;

        int mid;
        // 寻找中序数组位置作为切割点,同时进行中序数据的切割
        for (int i = 0; i < inorderEnd; i++) {
            if (root->val == inorder[i]) {
                mid = i;
                break;
            }
        }
        // 统一左闭右开 [inorderLeftBegin, inorderRightEnd)
        int inorderLeftBegin = inorderBegin;
        int inorderLeftEnd = mid;

        int inorderRightBegin = inorderLeftEnd + 1;
        int inorderRightEnd = inorderEnd;
 
        // 接下来进行后序数组的切割
        // 按照切割后的中序数组的 长度
        int postorderLeftBegin = postorderBegin;
        int postorderLeftEnd = postorderBegin + (inorderLeftEnd - inorderLeftBegin);

        int postorderRightBegin = postorderLeftEnd;
        int postorderRightEnd = postorderEnd - 1;

        root->left = traversal(inorder, inorderLeftBegin, inorderLeftEnd, postorder, postorderLeftBegin, postorderLeftEnd);
        root->right = traversal(inorder, inorderRightBegin, inorderRightEnd, postorder, postorderRightBegin, postorderRightEnd);
        return root;
    }
};

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

LeetCode-105-题目链接

容易理解版本

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return traversal(preorder, inorder);
    }
    TreeNode* traversal(vector<int>& preorder, vector<int>& inorder) {
        if (preorder.size() == 0 || inorder.size() == 0) return NULL;
        // 前序数组第一个元素为 结点元素
        TreeNode* root;
        root = new TreeNode(preorder[0]);
        if (preorder.size() == 1) {
            return root;
        }
        vector<int> inorderLeft, inorderRight;
        // 根据前序第一个结点元素 对中序 数组进行 分割
        for (int i = 0; i < inorder.size(); i++) {
            if (preorder[0] == inorder[i]) {
                break;
            }
            inorderLeft.push_back(inorder[i]);   
        }
        for (int i = inorderLeft.size() + 1; i < inorder.size(); i++) {
            inorderRight.push_back(inorder[i]);
        }
        // 此时继续根据 分割后的中序数组 对 前序数据进行分割
        vector<int> preorderLeft, preorderRight;
        for (int i = 1; i < inorderLeft.size() + 1; i++) {
            preorderLeft.push_back(preorder[i]);
        }
        for (int i = inorderLeft.size() + 1; i < preorder.size(); i++) {
            preorderRight.push_back(preorder[i]);
        }
        root->left = traversal(preorderLeft, inorderLeft);
        root->right = traversal(preorderRight, inorderRight);
        return root;
    } 
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值