需要熟练的树算法题

1、重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

>前序遍历 preorder = [3,9,20,15,7]
>中序遍历 inorder = [9,3,15,20,7]
>返回:
   3
  / \
 9  20
   /  \
  15   7
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = preorder.length;
        if (n == 0)
            return null;
        int rootVal = preorder[0], rootIndex = 0;
        // 找中序根的索引
        for (int i = 0; i < n; i++) {
            if (inorder[i] == rootVal) {
                rootIndex = i;
                break;
            }
        }
        TreeNode root = new TreeNode(rootVal);
        // 注意边界
        // left
        root.left = buildTree(
            Arrays.copyOfRange(preorder, 1, 1 + rootIndex), 
            Arrays.copyOfRange(inorder, 0, rootIndex));
        // right
        root.right = buildTree(
            Arrays.copyOfRange(preorder, 1 + rootIndex, n), 
            Arrays.copyOfRange(inorder, 1 + rootIndex, n));

        return root;
    }
}

2、二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

// 中序
public class T57 {
    public TreeLinkNode GetNext(TreeLinkNode pNode) {
        if (null == pNode) {
            return null;
        }
        // 两种情况
        if (null != pNode.right) {
            TreeLinkNode node = pNode.right;
            while (null != node.left) {
                node = node.left;
            }
            return node;
        }
        while (null != pNode.next) {
            TreeLinkNode parent = pNode.next;
            if (parent.left == pNode) {
                return parent;
            }
            pNode = pNode.next;
        }
        return null;
    }
}

3、树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。

>给定的树 A:

    3
   / \
  4   5
 / \
1   2
>给定的树 B:

  4 
 /
1
>返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
>输入:A = [1,2,3], B = [3,1]
>输出:false
>输入:A = [3,4,5,1,2], B = [4,1]
>输出:true
public class T17 {
	public boolean HasSubtree(TreeNode root1, TreeNode root2) {
        if (root1 == null || root2 == null)
            return false;
        return isSubtreeWithRoot(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
	}
    
	private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) {
        if (root2 == null)
            return true;
        if (root1 == null)
            return false;
        if (root1.val != root2.val)
            return false;
        return isSubtreeWithRoot(root1.left, root2.left) && isSubtreeWithRoot(root1.right, root2.right);
	}

}

3、二叉树的镜像

请完成一个函数,输入一个二叉树,该函数输出它的镜像。

>例如输入:

    4
  /   \
 2     7
/ \   / \
>1   3 6   9
>镜像输出:

    4
  /   \
 7     2
/ \   / \
>9   6 3   1
>输入:root = [4,2,7,1,3,6,9]
>输出:[4,7,2,9,6,3,1]
public class T18 {
    public void Mirror(TreeNode root) {
        // 判断
        if (root == null) return;
        swap(root);
        Mirror(root.left);
        Mirror(root.right);

    }

    private void swap(TreeNode root) {
        TreeNode t = root.left;
        root.left = root.right;
        root.right = t;
    }
}
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if (root == null) return null;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        TreeNode cur;
        while (!queue.isEmpty()) {
            cur = queue.poll();
            if(cur.left != null) queue.add(cur.left);
            if (cur.right != null) queue.add(cur.right);
            swap(cur);
        }
        return root;
    }

    private void swap(TreeNode root) {
        TreeNode t = root.left;
        root.left = root.right;
        root.right = t;
    }
}

4、对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

>例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

   1
  / \
 2   2
/ \ / \
>3  4 4  3
>但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

   1
  / \
 2   2
  \   \
  3    3
>输入:root = [1,2,2,3,4,4,3]
>输出:true
>输入:root = [1,2,2,null,3,null,3]
>输出:false
public class T58 {
    boolean isSymmetrical(TreeNode pRoot) {
        if (null == pRoot) {
            return true;
        }
        return comRoot(pRoot.left, pRoot.right);
    }

    private boolean comRoot(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }
		if (left == null || right == null) {
            return false;
        }
        if (left.val != right.val) {
            return false;
        }
		// 左右对比
        return comRoot(left.right, right.left) && comRoot(left.left, right.right);
    }
}

5.1、从上往下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

>如:
>给定二叉树: [3,9,20,null,null,15,7],

   3
  / \
 9  20
   /  \
  15   7
>返回:

>[3,9,20,15,7]
public class T22 {
    // 层序遍历 
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        // 需要用到队列
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.offer(root); // 第一次先加根入队
        while (!queue.isEmpty()) {
            int cnt = queue.size();
            // 如果队列不为空的话, 队列出一个元素
            while(cnt-- > 0) {
                TreeNode t = queue.poll();
                if (t == null) continue;
                list.add(t.val);
                queue.add(t.left);
                queue.add(t.right);
            }
        }
        return list;
    }
}

5.2、把二叉树打印多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

>输入
>{8,6,10,5,7,9,11}
>返回值
>[[8],[6,10],[5,7,9,11]]
public class T60 {

    ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
		Queue<TreeNode> queue = new LinkedList<>();
        queue.add(pRoot);
        while (!queue.isEmpty()) {
            ArrayList<Integer> list = new ArrayList<>();
            int cnt = queue.size();
            while (cnt-- > 0) {
                TreeNode node = queue.poll();
                if (node == null) continue;
                list.add(node.val);
                queue.add(node.left);
                queue.add(node.right);
            }
            if (list.size() != 0) ret.add(list);
        }
        return ret;
    }
}

5.3、按之字形顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

>输入
>{8,6,10,5,7,9,11}
>返回值
>[[8],[10,6],[5,7,9,11]]
public class T59 {
    public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(pRoot);
        boolean reverse = false;
        while (! queue.isEmpty()) {
            ArrayList<Integer> list = new ArrayList<>();
            int cnt = queue.size();
            while (cnt-- > 0) {
                TreeNode node = queue.poll();
                if (node == null) continue;
                list.add(node.val);
                queue.add(node.left);
                queue.add(node.right);
            }
            if (reverse) Collections.reverse(list);
            reverse = !reverse;
            if (list.size() != 0) ret.add(list);
        }
        return ret;
}

5.4 二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

>输入: [1,2,3,null,5,null,4]
>输出: [1, 3, 4]
>解释:

  1            <---
/   \
>2     3         <---
\     \
 5     4       <---

层序遍历,只保留最后一个结点的值

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if (root == null) return ret;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                TreeNode t = queue.poll();
                if (t.left != null) queue.add(t.left);
                if (t.right != null) queue.add(t.right);
                if (size == 0) ret.add(t.val);
            }
        }
        return ret;
    }
}

5.5 二叉树的左视图

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if (root == null) return ret;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            int size = queue.size();
            int tmp = size - 1;
            while (size-- > 0){
                TreeNode t = queue.poll();
                if(t.left != null) queue.add(t.left);
                if(t.right != null) queue.add(t.right);
                if(tmp == size) ret.add(t.val);
            }
        }
        return ret;
    }
}

6、二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。(ps:我们约定空树不是二叉搜素树)

>输入
>[4,8,6,12,16,14,10]
>返回值
>true
public class T23 {
    public boolean VerifySquenceOfBST(int [] sequence)  {
        if (sequence == null || sequence.length == 0) return false;
        return isBST(sequence, 0, sequence.length - 1);
    }
	private boolean isBST(int[] sequence, int first, int last) {
        if (last - first <= 1) {
            return true;
        }
        int rootVal = sequence[last];
        int cutIndex = first;
        while (cutIndex < last && sequence[curIndex] <= rootVal) { // 二叉搜索树特征
            cutIndex++;
        }
        for (int i = cutIndedx; i < last; i++) {
            if (sequence[i] < rootVal) return false;
        }
        return isBST(sequence, first, cutIndex - 1) && isBST(sequence, cutIndex, last - 1);
    }
}

7、二叉树中和为某一值的路径

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

>给定如下二叉树,以及目标和 target = 22,

             5
            / \
           4   8
          /   / \
         11  13  4
        /  \    / \
       7    2  5   1
>返回:

>[
  [5,4,11,2],
  [5,8,4,5]
>]
public class T24 {

    private ArrayList<ArrayList<Integer>> ret = new ArrayList<>();

    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
        backtracking(root, target, new ArrayList<>());
        return ret;
    }

    private void backtracking(TreeNode node, int target, ArrayList<Integer> path) {
        if (node == null)
            return;
        path.add(node.val);
        target -= node.val;
        if (target == 0 && node.left == null && node.right == null) {
            ret.add(new ArrayList<>(path));
        } else {
            backtracking(node.left, target, path);
            backtracking(node.right, target, path);
        }
        path.remove(path.size() - 1);
    }
}

8、二叉搜索树的第k个结点

给定一棵二叉搜索树,请找出其中第k大的节点。

>输入: root = [3,1,4,null,2], k = 1
  3
 / \
1   4
 \
  2
>输出: 4
>输入: root = [5,3,6,2,4,null,null,1], k = 3
      5
     / \
    3   6
   / \
  2   4
 /
1
>输出: 4
class Solution {
    private int ans = 0, count = 0;
    public int kthLargest(TreeNode root, int k) {
        // clarification:  root == null?   k <= 1?
        helper(root, k);
        return ans;
    }
    
    private void helper(TreeNode root, int k) {
        if (root.right != null) helper(root.right, k);
        
        if (++count == k) {
            ans = root.val;
            return;
        }
        
        if (root.left != null) helper(root.left, k);
    }
}

9.1、二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

>输入
>{1,2,3,4,5,#,6,#,#,7}
>返回值
>4
public class T38 {
    public int TreeDepth(TreeNode root) {
        // 递归取左和右的最大高度 + 1
        return root == null ? 0 : 1 + Math.max(TreeDepth(root.left), TreeDepth(root.right));
    }
}

// 迭代 bfs
class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        // 树不需要标记哦
        queue.add(root);
        int depth = 1;
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                TreeNode node = queue.poll();
                if (node.left == null && node.right == null)
                    return depth;
                if (node.left != null)
                    queue.add(node.left);
                if (node.right != null)
                    queue.add(node.right);
            }
            depth++;
        }
        return depth;
    }
}

9.2 二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

>给定二叉树

         1
        / \
       2   3
      / \     
     4   5    
>返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
class Solution {
    // 定义最大高度
    private int max = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        // 递归
        Depth(root);
        return max;
    }

    private int Depth(TreeNode root) {
        // 递归结束条件
        if (root == null) return 0;
        // 递归左的高度
        int l = Depth(root.left);
        // 递归右的高度
        int r = Depth(root.right);
        // 每次保持最大高度
        max = Math.max(max, l + r);
        // 返回左和右的最大高度加1
        return Math.max(l, r) + 1;
    }
}

10、平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

>给定二叉树 [3,9,20,null,null,15,7]

   3
  / \
 9  20
   /  \
  15   7
>返回 true 
>给定二叉树 [1,2,2,3,3,null,null,4,4]

      1
     / \
    2   2
   / \
  3   3
 / \
4   4
>返回 false
// 定义一个平衡标记,默认平衡
private boolean isBalanced = true;

public boolean IsBalanced_Solution(TreeNode root) {
    // 递归
    height(root);
    return isBalanced;
}

private int height(TreeNode root) {
    // 递归结束条件
    if (root == null || !isBalanced)
        return 0;
    // 递归左高度
    int left = height(root.left);
    // 递归右高度
    int right = height(root.right);
    // 绝对值是否大于1
    if (Math.abs(left - right) > 1)
        isBalanced = false;
    // 返回左和右的最大高度加1
    return 1 + Math.max(left, right);
}

11.1 非递归前序

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

>输入:root = [1,null,2,3]
>输出:[1,2,3]
>输入:root = []
>输出:[]
>输入:root = [1,2]
>输出:[1,2]
>输入:root = [1,null,2]
>输出:[1,2]
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    // 用栈的思想
    Stack<TreeNode> stack = new Stack<>();
    // 我们知道,前序:根左右
    // 添加根
    stack.push(root);
    while (!stack.isEmpty()) {
        // 弹根
        TreeNode node = stack.pop();
        // 判断是否为空
        if (node == null) continue;
        // 不为空,加val加入列表
        ret.add(node.val);
        // 先添加右,后左,这样下次就能先弹左
        stack.push(node.right);  
        stack.push(node.left);
    }
    return ret;
}

11.2 后序

给定一个二叉树,返回它的 后序 遍历。

>输入: [1,null,2,3]  
  1
   \
    2
   /
  3 

>输出: [3,2,1]
public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    // 还是栈思想,后序:左右根,倒过来:根右左:那么就是根前序的差不多
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        if (node == null) continue;
        ret.add(node.val);
        // 这里先添加左,保证弹出的是右
        stack.push(node.left);
        stack.push(node.right);
    }
    // 翻转就是后序
    Collections.reverse(ret);
    return ret;
}

11.3 中序

给定一个二叉树的根节点 root ,返回它的 中序 遍历。

>输入:root = [1,null,2,3]
>输出:[1,3,2]
>输入:root = []
>输出:[]
>输入:root = [1,2]
>输出:[2,1]
>输入:root = [1,null,2]
>输出:[1,2]
public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    if (root == null) return ret;
    // 还是栈:中序:左根右
    Stack<TreeNode> stack = new Stack<>();
    // 虚拟结点
    TreeNode cur = root;
    while (cur != null || !stack.isEmpty()) {
        while (cur != null) {
            // 一直左
            stack.push(cur);
            cur = cur.left;
        }
        // 保证弹出的左
        TreeNode node = stack.pop();
        ret.add(node.val);
        // 开始移动到右
        cur = node.right;
    }
    return ret;
}

12 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

>输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
>输出:3
>解释:节点 5 和节点 1 的最近公共祖先是节点 3
>输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
>输出:5
>解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
>输入:root = [1,2], p = 1, q = 2
>输出:1
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null)
            return root;
        // 如果根等于p或者q,直接返回根
        if (root == p || root == q)
            return root;
        // 递归左和pq比
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        // 递归右和pq比
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        // 同时不为空,则为根
        if (left != null && right != null)
            return root;
        // 左不空,则左
        else if (left != null)
            return left;
        // 右不空,则右
        else if (right != null)
            return right;
        return null;
    }
}

13. 合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

>输入: 
Tree 1                     Tree 2                  
         1                         2                             
        / \                       / \                            
       3   2                     1   3                        
      /                           \   \                      
     5                             4   7                  
>输出: 
>合并后的树:
     3
    / \
   4   5
  / \   \ 
 5   4   7
class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if (t1 == null && t2 == null) 
            return null;
        if (t1 == null) 
            return t2;
        if (t2 == null) 
            return t1;
        TreeNode root = new TreeNode(t1.val + t2.val);
        root.left = mergeTrees(t1.left, t2.left);
        root.right = mergeTrees(t1.right, t2.right);
        return root; 
    }
}

    public TreeNode mergeTrees2(TreeNode t1, TreeNode t2) {
        if (t1 == null && t2 == null) 
            return null;
        if (t1 == null) 
            return t2;
        if (t2 == null) 
            return t1;
        // 先合并根节点
        t1.val += t2.val;
        // 再递归合并左右子树
        t1.left = mergeTrees(t1.left, t2.left);
        t1.right = mergeTrees(t1.right, t2.right);
        return t1;
    }
class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(t1);
        queue.offer(t2);
        while(!queue.isEmpty()){
            TreeNode node1 = queue.poll();
            TreeNode node2 = queue.poll();
            //合并两个值
            node1.val += node2.val;
            //左子树都不为空
            if(node1.left != null && node2.left!=null){
                queue.offer(node1.left);
                queue.offer(node2.left);
            }
            if(node1.left == null)
                node1.left = node2.left;
            //右子树都不为空
            if(node1.right != null && node2.right != null){
                queue.offer(node1.right);
                queue.offer(node2.right);
            }
            if(node1.right == null)
                node1.right = node2.right;
        }
        return t1;
    }
}

14. 不同的二叉搜索树

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?

>输入: 3
>输出: 5
>解释:
>给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

  1         3     3      2      1
   \       /     /      / \      \
    3     2     1      1   3      2
   /     /       \                 \
  2     1         2                 3

动态规划

假设n个节点存在二叉排序树的个数是G(n),令f(i)为以i为根的二叉搜索树的个数

即有:G(n) = f(1) + f(2) + f(3) + f(4) + … + f(n)

n为根节点,当i为根节点时,其左子树节点个数为[1,2,3,…,i-1],右子树节点个数为[i+1,i+2,…n],所以当i为根节点时,其左子树节点个数为i-1个,右子树节点为n-i,即f(i) = G(i-1)*G(n-i),

上面两式可得:G(n) = G(0)G(n-1)+G(1)(n-2)+…+G(n-1)*G(0)

class Solution {
    public int numTrees(int n) {
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <=n; i++){
            for (int j = 1; j <= i; j++){
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        return dp[n];
    }
}

222. 完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

>输入:root = [1,2,3,4,5,6]
>输出:6
>输入:root = []
>输出:0
class Solution {
    public int countNodes(TreeNode root) {
        return root == null ? 0 : 1 + countNodes(root.left) + countNodes(root.right);
    }
}

98. 验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

>输入:
   2
  / \
 1   3
>输出: true
>输入:
   5
  / \
 1   4
    / \
   3   6
>输出: false
>解释: 输入为: [5,1,4,null,null,3,6]
    根节点的值为 5 ,但是其右子节点值为 4 
class Solution {
    public boolean isValidBST(TreeNode root) {
        return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    public boolean validate(TreeNode node, long min, long max) {
        if (node == null)
            return true;
        if (node.val <= min || node.val >= max)
            return false;
        return validate(node.left, min, node.val) && validate(node.right, node.val, max);
    }
}

257. 二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。

>输入:

  1
/   \
>2     3
\
 5

>输出: ["1->2->5", "1->3"]

>解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
class Solution {
    private List<String> res = new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        dfs(root, new StringBuilder());
        System.out.println(res.toString());
        return res;
    }

    public void dfs(TreeNode node, StringBuilder path) {
        if (node == null)
            return;
        path.append(node.val);
        if (node.left == null && node.right == null) {
            res.add(path.toString());
            return;
        } else {
            dfs(node.left, new StringBuilder(path).append("->"));
            dfs(node.right, new StringBuilder(path).append("->"));
        }
        // path.deleteCharAt(path.length() - 1);
    }
}

124. 二叉树中的最大路径和

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

>输入:root = [1,2,3]
>输出:6
>解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6
>输入:root = [-10,9,20,null,null,15,7]
>输出:42
>解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42
class Solution {
    int max = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        help(root);
        return max;
    }

    int help(TreeNode root) {
        if (root == null) 
            return 0;
        int left = help(root.left);
        int right = help(root.right);
        max = Math.max(max, left + right + root.val);
        int res = root.val + Math.max(left, right);
        return res > 0 ? res : 0;
    }
}

814. 二叉树剪枝

给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1。

返回移除了所有不包含 1 的子树的原二叉树。

( 节点 X 的子树为 X 本身,以及所有 X 的后代。)

>输入: [1,null,0,0,1]
>输出: [1,null,0,null,1]
>输入: [1,0,1,0,0,0,1]
>输出: [1,null,1,null,1]
>输入: [1,1,0,1,1,0,1,0]
>输出: [1,1,0,1,1,null,1]
class Solution {
    public TreeNode pruneTree(TreeNode root) {
        if (root == null)
            return null;
        root.left = pruneTree(root.left);
        root.right = pruneTree(root.right);
        if (root.left == null && root.right == null && root.val == 0)
            return null;
        return root;
    }
}

1026. 节点与其祖先之间的最大差值

给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。

(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)

>输入:root = [8,3,10,1,6,null,14,null,null,4,7,13]
>输出:7
>解释: 
>我们有大量的节点与其祖先的差值,其中一些如下:
>|8 - 3| = 5
>|3 - 7| = 4
>|8 - 1| = 7
>|10 - 13| = 3
>在所有可能的差值中,最大值 7 由 |8 - 1| = 7 得出。
>输入:root = [1,null,2,null,0,3]
>输出:3
class Solution {
    public int maxAncestorDiff(TreeNode root) {
        int left = dfs(root.left, root.val, root.val);
        int right = dfs(root.right, root.val, root.val);
        return Math.max(left, right);
    }

    public int dfs(TreeNode root, int max, int min) {
        if (root == null)
            return 0;
        max = Math.max(root.val, max);
        min = Math.min(root.val, min);
        if (root.left == null && root.right == null)
            return max - min;
        int left = dfs(root.left, max, min);
        int right = dfs(root.right, max, min);
        return Math.max(left, right);
    }
}

本博客所有文章除特别声明外,大部分为学习心得,欢迎与博主联系讨论