代码随想录算法训练营第18天|513. 找树左下角的值,路径总和,从中序与后序遍历序列构造二叉树

513. 找树左下角的值

  • 层序遍历法(取最后一层的第一个值)
class Solution {
    public int findBottomLeftValue(TreeNode root) {
            Queue<TreeNode> que = new LinkedList<TreeNode>();
            if(root == null) return 0;
            int res = 0;
            que.offer(root);
            while(!que.isEmpty()){
                  int size = que.size();
                  for(int i = 0; i< size; i++){
                      TreeNode node = que.poll();
                      if(i == 0) res = node.val;
                      if(node.left != null) que.offer(node.left);
                      if(node.right != null) que.offer(node.right); 
                  }
            }
            return res;
    }
}
  • 递归 + 回溯
    在这里插入图片描述
class Solution {
    int maxDepth = Integer.MIN_VALUE;
    int res = 0;
    public int findBottomLeftValue(TreeNode root) {
           traversal(root,0);
           return res;
    }

    public void traversal(TreeNode root, int depth){
            if(root.left == null && root.right == null){
                 if(depth > maxDepth){
                     maxDepth = depth;
                     res = root.val;
                 }
                 return;
            }

            if(root.left != null){
                depth++;
                traversal(root.left, depth);
                depth--; // 回溯
            }
            if(root.right != null){
                depth++;
                traversal(root.right, depth);
                depth--; // 回溯
            }
    }
}

路径总和

这里的递归需要注意的地方是,是从除了根节点以外的节点开始遍历,所以在传参时需要减去根节点的值。

    1. 路径总和
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
            // 用节点和与目标值做减法如果为0则有目标路径
            if (root == null) return false;
            return traversal(root,targetSum - root.val);
            
    }

    public boolean traversal(TreeNode root, int target){
          if(root.left == null && root.right == null && target == 0)
                    return true;
            if(root.left == null && root.right == null && target != 0)
                    return false;
            // 左
            if(root.left != null){
                target -= root.left.val;
                if(traversal(root.left,target)) return true;
                target += root.left.val; // 回溯
            }
            // 右
            if(root.right != null){
                target -= root.right.val;
                if(traversal(root.right,target)) return true;
                target += root.right.val; // 回溯
            }
            return false;
    }
}
  • 路径总和ii
    以下为小白写法,这里也是把根节点和其他节点分开处理
class Solution {
    
    public List<Integer> path = new LinkedList<>(); // 存放暂时路径
    public List<List<Integer>> res = new ArrayList<>(); // 存放结果集
    
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
            if(root == null) return res;
            path.add(root.val); // 加入根节点
            traversal(root,targetSum - root.val);
            return res;
    }

    public void traversal(TreeNode root, int target){
        if(root.left == null && root.right == null && target == 0){
             res.add(new ArrayList<>(path));
             return;
        }
        
        if(root.left != null){
             path.add(root.left.val);
             target -= root.left.val;
             traversal(root.left,target);
             target += root.left.val;
             path.remove(path.size() - 1);
        }

        if(root.right != null){
            path.add(root.right.val);
            target -= root.right.val;
            traversal(root.right,target);
            target += root.right.val;
            path.remove(path.size() - 1);
        }   
    }
}

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

跟着卡哥思路写的第一版,性能不太行,空间时间浪费太多。

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(postorder.length == 0 || inorder.length == 0) return null;
        return traversal(inorder,postorder);
    }

    public TreeNode traversal(int[] inorder, int[] postorder){
        if(postorder.length == 0) return null;

        int rootValue = postorder[postorder.length - 1];
        TreeNode root = new TreeNode(rootValue);

        if(postorder.length == 1) return root;

        int i = 0;
        for(; i<inorder.length; i++){
             if(inorder[i] == rootValue) break;
        }
        // 切割数组左闭右开原则
        int[] inLeft = Arrays.copyOfRange(inorder,0,i); 
        int[] inRight = Arrays.copyOfRange(inorder,i+1,inorder.length);

        int[] postLeft = Arrays.copyOfRange(postorder,0,inLeft.length); // 这里需要包含到左侧边界的数字
        int[] postRight = Arrays.copyOfRange(postorder,inLeft.length,postorder.length-1); // 这里需要去除最后的根节点

        root.left = traversal(inLeft,postLeft);
        root.right = traversal(inRight,postRight);

        return root;
    }
}
  • 这里利用哈希表记录中序遍历的数组,这样做非常方便元素的位置查找。
  • 把递归传递的参数从新的数组变成数组下标,节约空间。
class Solution {
    Map<Integer, Integer> map = new HashMap<>(); // to record the location of each node
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(inorder.length == 0 || postorder.length == 0) return null;
            for(int i=0;i<inorder.length;i++){
                map.put(inorder[i],i);
            }
            // 保持左闭右开原则
            return findNode(inorder, 0,inorder.length, postorder, 0,postorder.length);
    }

    public TreeNode findNode(int[] inorder, int inS, int inE, int[] postorder, int postS, int postE){
           if(inE <= inS || postE <= postS) return null;

           int index = map.get(postorder[postE - 1]); // 找到根节点的位置
           TreeNode root = new TreeNode(inorder[index]);
           

           int leftLen = index - inS; // 记录左子树长度

           root.left = findNode(inorder, inS, index, postorder, postS, postS + leftLen);
           root.right = findNode(inorder, index + 1, inE, postorder, postS + leftLen, postE - 1); // 这里记住要删掉最后的根节点
			
           return root;
           
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值