算法训练day18|二叉树part05

513.找树左下角的值

思路:用前序遍历(因为先遍历左边),并且遍历的时候记录节点的深度。每次深度更新的时候去记录下深度变大时节点的数值。由于先遍历左节点,所以最后得到的值就是树的最后一行最左边的值

总结:

迭代法更优:

层序遍历更直观,最后一层的第一个就是返回值。记录每层的第一个数值即可

遍历法:

前中后序都可以,都是优先遍历左节点

减少赋值的次数:只在叶子节点,并且最大深度更新的时候赋值。由于优先遍历左节点,所以最大深度更新的时候就是最左侧的节点。

class Solution {
    private int Deep = -1;
    private int value = 0;
    public int findBottomLeftValue(TreeNode root) {
        value = root.val;
        findLeftValue(root,0);
        return value;
    }

    private void findLeftValue (TreeNode root,int deep) {
        if (root == null) return;
        if (root.left == null && root.right == null) {
            if (deep > Deep) {
                value = root.val;
                Deep = deep;
            }
        }
        findLeftValue(root.left,deep + 1);
        findLeftValue(root.right,deep + 1);
    }
}
//迭代法
class Solution {

    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int res = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode poll = queue.poll();
                if (i == 0) {
                    res = poll.val;
                }
                if (poll.left != null) {
                    queue.offer(poll.left);
                }
                if (poll.right != null) {
                    queue.offer(poll.right);
                }
            }
        }
        return res;
    }
}

112. 路径总和

思路:回溯来来追溯路径和,满足条件就返回true

总结:

没有中的逻辑,所以前中后序都一样,(其实前序位置更改变量,后续位置做回溯)

什么时候需要返回值

再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

引用自:代码随想录

  • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
  • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况

113题中不要跟112的类型搞混,113需要遍历整个二叉树,不能提前返回

//112
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root==null)return false;
        if(root.left==null&&root.right==null&&targetSum==root.val)return true;
        targetSum-=root.val;
        
        
        boolean right = hasPathSum(root.right,targetSum);
        boolean left = hasPathSum(root.left,targetSum);
        // targetSum+=root.val;
        return right||left;


    }
}
//迭代
class solution {
    public boolean haspathsum(treenode root, int targetsum) {
        if(root == null) return false;
        stack<treenode> stack1 = new stack<>();
        stack<integer> stack2 = new stack<>();
        stack1.push(root);
        stack2.push(root.val);
        while(!stack1.isempty()) {
            int size = stack1.size();

            for(int i = 0; i < size; i++) {
                treenode node = stack1.pop();
                int sum = stack2.pop();

                // 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
                if(node.left == null && node.right == null && sum == targetsum) {
                    return true;
                }
                // 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
                if(node.right != null){
                    stack1.push(node.right);
                    stack2.push(sum + node.right.val);
                }
                // 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
                if(node.left != null) {
                    stack1.push(node.left);
                    stack2.push(sum + node.left.val);
                }
            }
        }
        return false;
    }
}

113
class Solution {
    List<List<Integer>> res;
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        res = new LinkedList<>();
        LinkedList<Integer> path = new LinkedList<>();
        traverse(root,path,targetSum);
        return res;
    }
    public void traverse(TreeNode root,LinkedList<Integer> path, int targetSum) {
        if(root==null)return;
        
        targetSum-=root.val;
        
        path.addLast(root.val);
        if(root.left==null&&root.right==null&&targetSum==0){
            res.add(new LinkedList<>(path));
            // return;此处不能有return否则后面的回溯无法完成,要搜索整颗二叉树
        }
        traverse(root.right,path,targetSum);
        traverse(root.left,path,targetSum);
        path.removeLast();
        // targetSum+=root.val;
        


    }
}
//迭代
class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> result = new ArrayList<>();
        Stack<TreeNode> nodeStack = new Stack<>();
        Stack<Integer> sumStack = new Stack<>();
        Stack<ArrayList<Integer>> pathStack = new Stack<>();
        if(root == null)
            return result;
        nodeStack.add(root);
        sumStack.add(root.val);
        pathStack.add(new ArrayList<>());

        while(!nodeStack.isEmpty()){
            TreeNode currNode = nodeStack.peek();
            int currSum = sumStack.pop();
            ArrayList<Integer> currPath = pathStack.pop();
            if(currNode != null){
                nodeStack.pop();
                nodeStack.add(currNode);
                nodeStack.add(null);
                sumStack.add(currSum);
                currPath.add(currNode.val);
                pathStack.add(new ArrayList(currPath));
                if(currNode.right != null){
                    nodeStack.add(currNode.right);
                    sumStack.add(currSum + currNode.right.val);
                    pathStack.add(new ArrayList(currPath));
                }
                if(currNode.left != null){
                    nodeStack.add(currNode.left);
                    sumStack.add(currSum + currNode.left.val);
                    pathStack.add(new ArrayList(currPath));
                }
            }else{
                nodeStack.pop();
                TreeNode temp = nodeStack.pop();
                if(temp.left == null && temp.right == null && currSum == targetSum)
                    result.add(new ArrayList(currPath));
            }
        }
        return result;
    }
}

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

数组的区间定义一定要统一

写代码的时候可以把分割的数组打印出来,更好debug

前序后续无法确定唯一二叉树。找不到分割点e.g

学会打日志来调试(如何打日志有时候也是个技术活),不要脑动模拟,脑动模拟很容易越想越乱

1.判断后序数组是否为空,为空返回null节点

2.不为空的话,在后续遍历中找到末尾的根节点

3.依靠根节点,找到根节点在中序数组中的位置

4.切割中序数组,切成中序左,和中序右 (一定先切中序)

5.依据中序切割切割后序数组,切成后序左,和后序右

6.递归处理左区间右区间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值