代码随想录训练营Day18|树:513.找树左下角的值、112.路径总和、113.路径总和2、106.从中序和后序遍历序列构造二叉树、105.从前序和中序遍历序列构造二叉树

LeetCode513:找树的左下角的值

思路:利用层序遍历,每次result记录最左侧的节点,到最后一层result就更新为树的左下角。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int findBottomLeftValue(TreeNode root) {
        if(root == null){
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int result = root.val;
        while(!queue.isEmpty()){
            int size = queue.size();
            for(int i=0;i<size;i++){
                TreeNode node = queue.poll();
                if(i==0){// 记录最左侧节点的值
                    result = node.val;
                }
                if(node.left!=null){
                    queue.offer(node.left);
                }
                if(node.right!=null){
                    queue.offer(node.right);
                }
            }
        }
        return result;
    }
}

层序遍历会更加简单一点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        int ans = 0;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
            int size = que.size();
            for(int i=0;i<size;i++){
                TreeNode* node = que.front();
                if(i==0){
                    ans = node->val;
                }
                que.pop();
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return ans;
    }
};

LeetCode112:路径总和

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        // 递归+回溯
        if(root == null){
            return false;
        }
        boolean ans = helper(root, targetSum - root.val);// 在开始的位置对root特殊处理。不能放到里面去处理 会重复减。
        return ans;
    }
    public boolean helper(TreeNode node, int number){
        // 递归终止条件
        if(node.left == null && node.right == null && number == 0){
            return true;
        }
        else if(node.left == null && node.right == null && number != 0){
            return false;
        } 
        if(node.left!=null){
            number -= node.left.val; // 
            if(helper(node.left, number)){
                return true;
            }
            number += node.left.val; // 回溯
        }
        if(node.right!=null){
            number -= node.right.val;
            if(helper(node.right, number)){
                return true;
            }
            number += node.right.val;
        }
        return false;
    }
}
C++
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    bool getPath(TreeNode* node, int targetSum){
        // 递归的结束条件 有两个:
        // 1. 到了叶子节点 找到了;2. 到了叶子节点没有找到
        if(targetSum == 0 && node->left == NULL && node->right == NULL) return true;
        else if(targetSum != 0 && node->left == NULL && node->right == NULL) return false;
        if(node->left){
            if(getPath(node->left, targetSum - node->left->val)) // 如果下一层返回的是true 就直接向上返回true。 而且这里最好是这样写判断 不要在想之前一样写一个bool left再放到后面return 判断。
                return true;
        }
        if(node->right){
            if(getPath(node->right, targetSum - node->right->val))
                return true;
        }
        return false;
    }
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == NULL) return false;
        bool ans = getPath(root, targetSum-root->val);
        return ans;
    }


};

LeetCode113路径总和2

思路:与上题基本一致,只不过返回的结果是具体的路径。所以更能体现回溯的价值。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
            // 
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        if(root == null){
            return ans;
        }
        List<Integer> temp = new LinkedList<>();
        helper(root, targetSum-root.val, ans, temp);
        return ans;        
    
    }
    public void helper(TreeNode node, int number, List<List<Integer>> ans, List<Integer> temp){
        temp.add(node.val);
        if(node.left == null && node.right == null && number == 0){
            List<Integer> temp_ = new ArrayList<>(temp);
            ans.add(temp_);
        }
        else if(node.left == null && node.right == null && number!=0){
            return;
        }
        if(node.left != null){
            helper(node.left, number - node.left.val, ans, temp);
            temp.remove(temp.size() -1);
        }
        if(node.right != null){
            helper(node.right, number- node.right.val, ans, temp);
            temp.remove(temp.size() -1);
        }
    
    }
}
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:

    void traversal(TreeNode* node, int targetSum, vector<int>& ans_, vector<vector<int>>& ans){
        // 递归结束条件,还是要找到叶子结点判断val是否为零两种情况。
        // 这里的返回值设为viod比较好,不然范围ans_ 还是ans都是很麻烦的事,因此使用全局变量 或者传递这个变量比较好
        if(node->left == NULL && node->right == NULL && targetSum == 0){
            ans.push_back(ans_); // 找到了路径就在此时将找到的路径加到最终的二维数组去
            return;
        }
        if(node->left== NULL && node->right == NULL){
            return;
        }
        if(node->left){
            ans_.push_back(node->left->val); // 先将当前左子节点加到ans_ 里面去
            targetSum -= node->left->val; // 先将当前左子节点的val剪掉,
            traversal(node->left, targetSum, ans_, ans); // 递归,此时判断左子节点下面的路径时候符合要求
            targetSum += node->left->val; // 回溯, 将上一步加进去的左叶子节点值加回去,意味着返回父节点要往右子节点找了
            ans_.pop_back();  // 回溯
        }

        if(node->right){
            ans_.push_back(node->right->val);
            targetSum -= node->right->val;
            traversal(node->right, targetSum, ans_, ans);
            targetSum += node->right->val;
            ans_.pop_back();
        }
        return;
    }
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        // 这里必须用到回溯了,要返回所有的路径情况
        vector<vector<int>> ans;
        vector<int> ans_;
        ans.clear();
        ans_.clear();
        if(root == NULL) return ans;
        ans_.push_back(root->val);  // 根节点在一开始就要加到ans_里面去
        traversal(root, targetSum- root->val, ans_, ans);
        return ans;

    }
};

LeetCode106从中序和后序遍历构造二叉树

思路:
后序确定父节点,中序确定左右子树

  1. 通过后序找到根节点
  2. 通过根节点的值,在中序中遍历将其划分左右子树
  3. 通过左子树大小,在后序中遍历得到左,再得到右,(记得先将根节点删去)
  4. 递归中序和后序的左子树;递归中序和后序的右子树
  5. 返回root

关键点:在数组问题上 会遇见的左闭右开还是左闭右闭的问题,这里用的是左闭右闭。
有很多细节,例如:

  1. 使用public 一个map用来存放数组的值和索引,避免重复创建数组;
  2. 在递归传入参数的时候传递了inorder 和postorder的首位索引注意区间的开闭
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public Map<Integer, Integer> map = new HashMap<>(); 
    // 用map可以方便得到元素在数组中的索引和值。
    // 同时代码中没必要将左右区间都用数组表示出来,只要知道首尾索引就可以
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i], i);
        }
        return getNode(inorder, 0, inorder.length -1, postorder, 0, postorder.length-1);// 这里是左闭右闭
    }
    public TreeNode getNode(int[] inorder, int inStart, int inEnd, int[] postorder, int poStart, int poEnd){
        // 后序确定父节点,中序确定左右子树
        // 1. 通过后序找到根节点
        // 2. 通过根节点的值,在中序中遍历将其划分左右子树
        // 3. 通过左子树大小,在后序中遍历得到左,再得到右,(记得先将根节点删去)  
        // 4. 递归中序和后序的左子树;递归中序和后序的右子树
        // 5. 返回root
        if (inStart> inEnd || poStart > poEnd) {  // 不满足左闭右开,说明没有元素,返回空树
            return null;
        }
        // 下面的写法避免了重复创建数组来保存左右区间
        // 但是理解起来麻烦了点
        // 
        int index = map.get(postorder[poEnd]); // 确定父节点的位置
        TreeNode root  = new TreeNode(postorder[poEnd]);
        int indexLeft = index - inStart; // 确定左区间的长度,从而也可以得到有区间的长度。
        root.left = getNode(inorder, inStart, index-1, postorder, poStart, poStart+indexLeft-1);
        root.right = getNode(inorder, index+1,inEnd, postorder, poStart+indexLeft, poEnd-1);
        return root;
    }
}

完整的模板代码 便于理解。

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

        // 后序遍历数组最后一个元素,就是当前的中间节点
        int rootValue = postorder[postorder.size() - 1];
        TreeNode* root = new TreeNode(rootValue);

        // 叶子节点
        if (postorder.size() == 1) return root;

        // 找到中序遍历的切割点
        int delimiterIndex;
        for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }

        // 切割中序数组
        // 左闭右开区间:[0, delimiterIndex)
        vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
        // [delimiterIndex + 1, end)
        vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );

        // postorder 舍弃末尾元素
        postorder.resize(postorder.size() - 1);

        // 切割后序数组
        // 依然左闭右开,注意这里使用了左中序数组大小作为切割点
        // [0, leftInorder.size)
        vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
        // [leftInorder.size(), end)
        vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());

        root->left = traversal(leftInorder, leftPostorder);
        root->right = traversal(rightInorder, rightPostorder);

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

LeetCode105从前序和中序遍历序列构造二叉树

同116题一致。注意数组的左开右闭以及在递归时候**传入参数))的细节。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public Map<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i], i);
        }
        return getNode(preorder, 0, preorder.length-1, inorder, 0, inorder.length-1);
    }
    public TreeNode getNode(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd){
        if(preStart>preEnd || inStart>inEnd){
            return null;
        }
        int index = map.get(preorder[preStart]);
        TreeNode root = new TreeNode(preorder[preStart]);
        int lenLeft = index -inStart;
        root.left = getNode(preorder, preStart+1, preStart+lenLeft, inorder, inStart, inStart+lenLeft-1);
        root.right = getNode(preorder,preStart+lenLeft+1, preEnd, inorder, index+1, inEnd);
        return root;
    }
}
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    TreeNode* traversal(vector<int>& preorder, vector<int>& inorder){
        if(preorder.size() == 0) return NULL;

        int nodeValue = preorder[0];
        TreeNode* node =new TreeNode(nodeValue);
        if(preorder.size() == 1)return node;

        int cutIndex;
        for(cutIndex=0;cutIndex<inorder.size();cutIndex++){
            if(inorder[cutIndex] == nodeValue) break;
        }

        vector<int> leftinorder(inorder.begin(), inorder.begin()+cutIndex);
        vector<int> rightinorder(inorder.begin()+cutIndex+1, inorder.end());

        vector<int> leftpreorder(preorder.begin()+1, preorder.begin()+1 + leftinorder.size());
        vector<int> rightpreorder(preorder.begin()+1+leftinorder.size(), preorder.end());

        node->left = traversal(leftpreorder, leftinorder);
        node->right = traversal(rightpreorder, rightinorder);
        return node;
    }
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
            if(preorder.size() == 0 || inorder.size() == 0) return NULL;
            return traversal(preorder, inorder);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值