二叉树算法

89 阅读9分钟

1.前中后序遍历

www.nowcoder.com/practice/a9…

递归法

import javax.swing.tree.TreeNode;

import java.util.ArrayList;

import java.util.List;



/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */



public class Solution {



    public int[][] threeOrders (TreeNode root) {

        //三个集合,分别存储三种遍历结果

        List<Integer> list1 = new ArrayList<>();

        List<Integer> list2 = new ArrayList<>();

        List<Integer> list3 = new ArrayList<>();



        //调用函数计算遍历结果

        preOrder(root, list1);//前序

        inOrder(root, list2);//中序

        postOrder(root, list3);//后续



        //存放结果

        int[][] res = new int[3][list1.size()];

        for(int i = 0; i < list1.size(); i++){

            res[0][i] = list1.get(i);

            res[1][i] = list2.get(i);

            res[2][i] = list3.get(i);



        }

        //答案返回

        return res;

    }

    // 先序遍历函数

    public void preOrder(TreeNode root, List<Integer> list){

        //为空时结束遍历

        if(root == null){

            return;

        }

        //对左右子树进行递归的遍历

        list.add(root.val);

        preOrder(root.left, list);

        preOrder(root.right, list);

    }



    // 中序遍历函数

    public void inOrder(TreeNode root, List<Integer> list){

        //特判

        if(root == null){

            return;

        }

        //递归调用:对左右子树进行递归的遍历

        inOrder(root.left, list);

        list.add(root.val);

        inOrder(root.right, list);

    }



    // 后序遍历函数

    public void postOrder(TreeNode root, List<Integer> list){

        if(root == null){

            return;

        }

        //递归调用:对左右子树进行递归的遍历

        postOrder(root.left, list);

        postOrder(root.right, list);

        list.add(root.val);

    }



}

递归法从根节点开始,按照遍历的要求去不断递归节点,临界条件即为下个节点为空。对于递归顺序的安排,前序就在第一个添加,中序就第二个,后续就最后添加

非递归



import javax.swing.tree.TreeNode;

import java.util.ArrayList;

import java.util.List;

import java.util.Stack;



/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */



public class Solution {



    public int[][] threeOrders(TreeNode root) {

        //三个集合,分别存储三种遍历结果

        List<Integer> list1 = new ArrayList<>();

        List<Integer> list2 = new ArrayList<>();

        List<Integer> list3 = new ArrayList<>();



        //调用函数计算遍历结果

        preOrder(root, list1);//前序

        inOrder(root, list2);//中序

        postOrder(root, list3);//后续



        //存放结果

        int[][] res = new int[3][list1.size()];

        for (int i = 0; i < list1.size(); i++) {

            res[0][i] = list1.get(i);

            res[1][i] = list2.get(i);

            res[2][i] = list3.get(i);



        }

        //答案返回

        return res;

    }



    // 先序遍历函数

// 1.根节点入栈

//2.当栈非空时,栈顶出栈,把出栈的节点值添加到 list 结尾,

// 然后依次再入栈其右子节点和左子节点

//因为前序遍历要左子节点在右子节点前面,所以先入栈右子节点,后入栈左子节点

    public void preOrder(TreeNode root, List<Integer> list) {

        if (root == null) {

            return;

        }

        Stack<TreeNode> stack = new Stack<>();

        stack.push(root);

        while (!stack.isEmpty()) {//return elementCount == 0;

            TreeNode curr = stack.pop();

            list.add(curr.val);//栈顶出栈

            if (curr.right != null) {

                stack.push(curr.right);//压右

            }

            if (curr.left != null) {

                stack.push(curr.left);//压左

            }

        }

    }



    // 中序遍历函数

// 1.辅助变量 curr 初始化 root

//当栈非空或 curr 非 null 时,循环

//curr != null 时,说明还有左子节点存在,将 curr 入栈,并且将 curr 置为

// 它自己的左子节点

// (和前序遍历的区别在于这里遍历到先不保存到 list 中,出栈的时候再将其

// 保存到 list 中)

//curr == null 时,说明到二叉树左下的节点了,这时栈顶的父节点出栈赋

// 值给 curr ,并保存节点值到 list ,

// 将 curr 置为栈顶节点的右子节点继续循环

    public void inOrder(TreeNode root, List<Integer> list) {

        if (root == null) {

            return;

        }

        Stack<TreeNode> stack = new Stack<>();

        TreeNode curr = root;

        while (!stack.isEmpty() || curr != null) {

            if (curr != null) {

                stack.push(curr);

                curr = curr.left;//这里遍历到最左下方

            } else {

                curr = stack.pop();//当最左下方时,第一次出栈为最左的左节点

                list.add(curr.val);//1.这个节点没有子节点:则其右节点还为空,再次进入

                //else出栈这个左节点的父节点

                curr = curr.right;//2.有右节点:则进入if压入栈,在进行同样循环

            }//中序遍历实际就是找左节点,连续两次pop输出左节点和父节点,然后else压入

            //右节点再进行同样循环

        }

    }



    // 后序遍历函数

//    前序遍历从尾部添加元素,后序遍历从头部添加元素前序遍历去左子树,后序遍历去右子树

    public void postOrder(TreeNode root, List<Integer> list) {

        if (root == null) {

            return;

        }

        Stack<TreeNode> stack = new Stack<>();

        stack.push(root);

        while (!stack.isEmpty()) {

            TreeNode curr = stack.pop();

            list.add(0, curr.val);

            if (curr.left != null) {

                stack.push(curr.left);

            }

            if (curr.right != null) {

                stack.push(curr.right);

            }

        }

    }

}//实际是后续遍历的倒序输出

非递归主要利用Stack先进后出的性质

2.层次遍历

www.nowcoder.com/practice/04…

import java.util.*;

/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */

  

public class Solution {

    /**

     *

     * @param root TreeNode类

     * @return int整型ArrayList<arraylist><>>

     */

    public ArrayList levelOrder (TreeNode root) {

        // write code here

        ArrayList res = new ArrayList<>();//创建一个链表,用于存储

        if(root ==  null )

            return res;

        LinkedList<TreeNode> que = new LinkedList<>();

        que.offer(root);//用来插入指定的元素插入此优先级队列

        while(!que.isEmpty()){

            int len = que.size(); //len为前一个一层的个数,用来控制循环次数

            ArrayList list = new ArrayList<>();

            while(len > 0){

                TreeNode node = que.poll();//pol取的这个元素将从原队列删除;

                list.add(node.val);

                if(node.left != null)

                    que.offer(node.left);

                if(node.right != null)

                    que.offer(node.right);

                len--;

            } 

            res.add(list);

        }

        return res;

    }

}

利用队列先进先出的性质顺序输出每一层的节点,添加队列时也是从左往右的依次添加进去

3.之字形打印

www.nowcoder.com/practice/91…



import java.util.*;

/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */



public class Solution {

    /**

     *

     * @param root TreeNode类

     * @return int整型ArrayList<arraylist><>>

     */

    public ArrayList<ArrayList<Integer>> Print (TreeNode pRoot) {

        // write code here

        ArrayList<ArrayList<Integer>> res = new ArrayList<>();//创建一个链表,用于存储

        if(pRoot == null )

            return res;

        int x = 0;

        LinkedList<TreeNode> que = new LinkedList<>();

        que.offer(pRoot);//用来插入指定的元素插入此优先级队列

        while(!que.isEmpty()){

            int len = que.size(); //len为前一个一层的个数,用来控制循环次数

            ArrayList list = new ArrayList<>();

            while(len > 0){

                TreeNode node = que.poll();//pol取的这个元素将从原队列删除;

                if(x%2==0)

                    list.add(node.val);

                    else

                    list.add(0,node.val);

                if(node.left != null)

                    que.offer(node.left);

                if(node.right != null)

                    que.offer(node.right);

                len--;

            }

            x++;

            res.add(list);

        }

        return res;

    }

}

层次打印将奇数层正序打印,偶数层倒序

4.两个节点的最近公共祖先

www.nowcoder.com/practice/e0…

本题保证二叉树中每个节点的val值均不相同。

import java.util.*;



/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */

 class Solution {

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

        if (root == null || root == p || root == q) { // 递归结束条件

            return root;

        }



        // 后序遍历

        TreeNode left = lowestCommonAncestor(root.left, p, q);

        TreeNode right = lowestCommonAncestor(root.right, p, q);



        if(left == null && right == null) { // 若未找到节点 p 或 q

            return null;

        }else if(left == null && right != null) { // 若找到一个节点

            return right;

        }else if(left != null && right == null) { // 若找到一个节点

            return left;

        }else { // 若找到两个节点

            return root;

        }

    }

}



public class Solution {

    /**

     * 

     * @param root TreeNode类 

     * @param o1 int整型 

     * @param o2 int整型 

     * @return int整型

     */

        public int lowestCommonAncestor(TreeNode root, int o1, int o2) {

        //记录遍历到的每个节点的父节点。

        Map<Integer, Integer> parent = new HashMap<>();

        Queue<TreeNode> queue = new LinkedList<>();

        parent.put(root.val, Integer.MIN_VALUE);//根节点没有父节点,给他默认一个值

        queue.add(root);

        //直到两个节点都找到为止。

        while (!parent.containsKey(o1) || !parent.containsKey(o2)) {

            //队列的方法层序遍历,这里poll方法是出队,

            TreeNode node = queue.poll();

            if (node.left != null ) {

                //左子节点不为空,记录下他的父节点

                parent.put(node.left.val, node.val);

                //左子节点不为空,把它加入到队列中

                queue.add(node.left);

            }

            //右节点同上

            if (node.right != null ) {

                parent.put(node.right.val, node.val);

                queue.add(node.right);

            }

        }

        Set<Integer> ancestors = new HashSet<>();

        //记录下o1和他的祖先节点,从o1节点开始一直到根节点。

        while (parent.containsKey(o1)) {

            ancestors.add(o1);

            o1 = parent.get(o1);

        }

        //查看o1和他的祖先节点是否包含o2节点,如果不包含再看是否包含o2的父节点……

        while (!ancestors.contains(o2))

            o2 = parent.get(o2);

        return o2;

    }

}

5.重建二叉树

www.nowcoder.com/practice/8a…

通过前序遍历的第一个得到根节点的值,那么在中序遍历中,根节点左侧的即全为左子树的部分,右边的为右子树的节点。并且前序遍历后面的值即为连续的左子树的节点和右子树节点,那么根据中序遍历中根节点的位置就可以找到前序遍历中左右子树的分割点。那么再对分割出两部分重复上面操作,即可重建。



import javax.swing.tree.TreeNode;

import java.util.HashMap;

 /**

 * Definition for binary tree

 * public class TreeNode {

 *     int val;

 *     TreeNode left;

 *     TreeNode right;

 *     TreeNode(int x) { val = x; }

 * }

 */

public class Solution {

    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {

        // 判断特殊情况

        if (pre == null || pre.length == 0 || in == null || in.length == 0) {

            return null;

        }



        // key : 中序遍历元素的值;

        // value : 中序遍历元素的值 对应的 下标

        // 可以以O(1)的时间复杂度找到元素在中序遍历中对应的下标

        HashMap<Integer, Integer> map = new HashMap<>();

        for (int i = 0; i < in.length; i++) {

            map.put(in[i], i);

        }



        // 返回在 pre[0...pre.length-1] , in[0, in.length-1] 范围上建立二叉树的根节点

        return process(pre, 0, pre.length - 1,

                0, map);



    }





    /**

 *  @param pre 前序遍历的数组

 *  @param pL  使用到的 前序遍历的数组 的左边界,闭区间

 *  @param pR  使用到的 前序遍历的数组 的右边界,闭区间

 *  @param inL 使用到的 中序遍历的数组 的左边界,闭区间

 *  @param inR 使用到的 中序遍历的数组 的右边界,闭区间

 *  @param map 方便找到元素在中序遍历中对应的下标 需要的 数据结构

 *  @return 在使用到的 前序遍历数组、中序遍历数组中;生成该范围内的二叉树,返回这个二叉树的 根节点

 */

 public TreeNode process(int[] pre, int pL, int pR,

                            int inL,

                            HashMap<Integer, Integer> map) {

        // 越界情况,没有二叉树存在,直接返回 null

        if (pL > pR) {

            return null;

        }

        // 只有一个元素,就是根节点,直接返回

        if (pL == pR) {

            return new TreeNode(pre[pL]);

        }

        // 前序遍历的第一个元素就是 根节点

        TreeNode root = new TreeNode(pre[pL]);

        // 找到 根节点在 中序遍历数组里的 下标

        int inIndex = map.get(pre[pL]);

        // 这里确定新的遍历范围,leftTreeSize即左子树所有节点的个数

        int leftTreeSize = inIndex - inL;

        //左子树

        // 前序遍历,pL + 1为左子树节点的开始,即下一个根节点,pL + leftTreeSize左子树

        //节点结束的位置,后面剩下的为右子树的

        // 中序遍历中inL为左子树的开始,inIndex - 1:inIndex为根节点的位置

        //因此减一为左子树结束的位置

        root.left = process(pre, pL + 1, pL + leftTreeSize,

                inL,

                map);

        //右子树

        //pL + leftTreeSize + 1:为右子树的前序遍历第一结点,即等下的根节点,pR为右子树节

        //点结束位置

        //inIndex + 1:中序遍历中右子树的开始位置

        root.right = process(pre, pL + leftTreeSize + 1, pR,

                inIndex + 1,

                map);

        return root;

    }



}

6.输出二叉树的右视图

www.nowcoder.com/practice/c9…

先构建,再层序遍历输出视图



import javax.swing.tree.TreeNode;

import java.util.*;



 /**

 * Definition for binary tree

 * public class TreeNode {

 *     int val;

 *     TreeNode left;

 *     TreeNode right;

 *     TreeNode(int x) { val = x; }

 * }

 */

public class Solution {

    public int[] solve (int[] xianxu, int[] zhongxu) {

        int[] pre=xianxu;

        int[] in=zhongxu;

        // 判断特殊情况

        if (pre == null || pre.length == 0 || in == null || in.length == 0) {

            return null;

        }



        // key : 中序遍历元素的值;

        // value : 中序遍历元素的值 对应的 下标

        // 可以以O(1)的时间复杂度找到元素在中序遍历中对应的下标

        HashMap<Integer, Integer> map = new HashMap<>();

        for (int i = 0; i < in.length; i++) {

            map.put(in[i], i);

        }



        // 返回在 pre[0...pre.length-1] , in[0, in.length-1] 范围上建立二叉树的根节点

        TreeNode root= process(pre, 0, pre.length - 1,

                0, in.length - 1,

                map);

        Queue<TreeNode> q = new LinkedList<>();

        if (root == null) return new int[0];

        q.add(root);

        List<Integer> list = new ArrayList<>();

        while (!q.isEmpty()) {

            for (int i = q.size()-1; i >= 0; i--) {

                TreeNode node = q.poll();

                if (i == 0) list.add(node.val);

                if (node.left != null) q.add(node.left);

                if (node.right != null) q.add(node.right);

            }

        }

        int[] res = new int[list.size()];

        for (int i = 0; i < list.size(); i++) {

            res[i] = list.get(i);

        }

        return res;

    }







    /**

 *  @param pre 前序遍历的数组

 *  @param pL  使用到的 前序遍历的数组 的左边界,闭区间

 *  @param pR  使用到的 前序遍历的数组 的右边界,闭区间

 *  @param inL 使用到的 中序遍历的数组 的左边界,闭区间

 *  @param inR 使用到的 中序遍历的数组 的右边界,闭区间

 *  @param map 方便找到元素在中序遍历中对应的下标 需要的 数据结构

 *  @return 在使用到的 前序遍历数组、中序遍历数组中;生成该范围内的二叉树,返回这个二叉树的 根节点

 */

 public TreeNode process(int[] pre, int pL, int pR,

                            int inL, int inR,

                            HashMap<Integer, Integer> map) {

        // 越界情况,没有二叉树存在,直接返回 null

        if (pL > pR || inL > inR) {

            return null;

        }

        // 只有一个元素,就是根节点,直接返回

        if (pL == pR || inL == inR) {

            return new TreeNode(pre[pL]);

        }

        // 前序遍历的第一个元素就是 根节点

        TreeNode root = new TreeNode(pre[pL]);

        // 找到 根节点在 中序遍历数组里的 下标

        int inIndex = map.get(pre[pL]);

        // 这里确定新的遍历范围,leftTreeSize即左子树所有节点的个数

        int leftTreeSize = inIndex - inL;

        //左子树

        // 前序遍历,pL + 1为左子树节点的开始,即下一个根节点,pL + leftTreeSize左子树节点结束的位置,后面剩下的为右子树的

        // 中序遍历中inL为左子树的开始,inIndex - 1:inIndex为根节点的位置,因此减一为左子树结束的位置

        root.left = process(pre, pL + 1, pL + leftTreeSize,

                inL, inIndex - 1,

                map);

        //右子树

        //pL + leftTreeSize + 1:为右子树的前序遍历第一结点,即等下的根节点,pR为右子树节点结束位置

        //inIndex + 1:中序遍历中右子树的开始位置

        root.right = process(pre, pL + leftTreeSize + 1, pR,

                inIndex + 1, inR,

                map);

        return root;

    }



}

7.二叉树的最大深度

www.nowcoder.com/practice/8a…



import javax.swing.tree.TreeNode;



/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */



public class Solution {

    /**

 *

 *  @param root TreeNode类

 *  @return int整型

 */

 public int maxDepth (TreeNode root) {

        // write code here

        // 递归终止

        if(root == null) {

            return 0;

        }

        // dfs,先递归左子结点,再递归右子结点,最后求出每一子树的深度的最大值

        //+1为加上自己的那一层再返回

        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;

    }

}

8.判断是不是平衡二叉树

www.nowcoder.com/practice/8b…

import javax.swing.tree.TreeNode;

public class Solution {

    boolean isBalanced = true;

    public boolean IsBalanced_Solution(TreeNode root) {

        TreeDepth(root);

        return isBalanced;

    }

    public int TreeDepth(TreeNode root) {

        if (root == null)

            return 0;

        int l = TreeDepth(root.left);

        if (l == -1) return -1;  // 提前返回

        int r = TreeDepth(root.right);

        if (r == -1) return -1;  // 提前返回

        if (Math.abs(l - r) > 1) {

            isBalanced = false;  // 不是平衡树

            return -1;  // 加一个标记-1,已经不可能是平衡树了,通过上面的if返回

        }

        return Math.max(l, r) + 1;

    }

}

9.根节点到叶子节点的所有路径和

www.nowcoder.com/practice/18…

利用两个栈来存储节点和对应的值,这里节点在栈里的深度,其值对应的也是相同的深度,这样当节点出栈时,其所在路径已经累计的值也相应出栈。那么根据是叶子节结束这条路径的遍历,不是这继续将其子节点和子节点累计的值相应的压入栈。

/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */

public class Solution {

    /**

 *  @param root TreeNode类

 *  @return int整型

 */

 public int sumNumbers(TreeNode root) {

        //如果根节点是空,直接返回0即可

        if (root == null)

            return 0;

        //两个栈,一个存储的是节点,一个存储的是节点对应的值

        Stack<TreeNode> nodeStack = new Stack<>();

        Stack<Integer> valueStack = new Stack<>();

        //全局的,统计所有路径的和

        int res = 0;

        nodeStack.add(root);

        valueStack.add(root.val);

        while (!nodeStack.isEmpty()) {

            //当前节点和当前节点的值同时出栈

            TreeNode node = nodeStack.pop();

            int value = valueStack.pop();

            if (node.left == null && node.right == null) {

                //如果当前节点是叶子结点,说明找到了一条路径,把这条

                //路径的值加入到全局变量res中

                res += value;

            } else {

                //如果不是叶子节点就执行下面的操作

                if (node.right != null) {

                    //把子节点和子节点的值分别加入到栈中,这里子节点的值

                    //就是父节点的值*10+当前节点的值

                    nodeStack.push(node.right);

                    valueStack.push(value * 10 + node.right.val);

                }

                if (node.left != null) {

                    nodeStack.push(node.left);

                    valueStack.push(value * 10 + node.left.val);

                }

            }

        }

        return res;

    }

}

10.二叉树中和为某一值的路径

www.nowcoder.com/practice/b7…

节点的值存在负数的可能,因此无法提前剪枝。使用LinkedList存储当前深度遍历的路径。到叶子节点符合则将路径添加进去,不符合则删除当前节点,向上回溯继续递归其他路径。

import java.util.ArrayList;

import java.util.LinkedList;



 /**

 * public class TreeNode {

 * int val = 0;

 * TreeNode left = null;

 * TreeNode right = null;

 * <p>

 * public TreeNode(int val) {

 * this.val = val;

 * }

 * }

 */

public class Solution {

    //初始化集合

    ArrayList res = new ArrayList<>();

    LinkedList path = new LinkedList<>();



    public ArrayList FindPath(TreeNode root, int target) {

        dfs(root, target);

        return res;

    }



    public void dfs(TreeNode root, int tar) {

        //叶子节点结束递归

        if (root == null) {

            return;

        }

        //将root节点放入路径集合

        path.add(root.val);

        //更新目标值,每放入一个节点,目标值应该相应减去对应节点的值,直到目标值为0

        tar -= root.val;

        //如果目标值减到了0 && 左节点为空 && 右节点为空 证明树已遍历完,此路径为目标路径

        if (tar == 0 && root.left == null && root.right == null) {

            res.add(new ArrayList(path));

        }

        

        // 递归左右子树

        dfs(root.left, tar);

        dfs(root.right, tar);

        //删除当前节点,在回溯过程中,此节点不在新路径上

        path.removeLast();

    }

}

11.是否为搜索二叉树和完全二叉树

www.nowcoder.com/practice/f3…

判断中序遍历结果是否是升序

完全二叉树

1.层次遍历直至遇到第一个空节点

2.完全二叉树在遇到空节点之后剩余的应当全是空节点

import java.util.ArrayList;

import java.util.LinkedList;

import java.util.Queue;



/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */

public class Solution {

    /**

 *  @param root TreeNode类 the root

 *  @return bool布尔型一维数组

 */

 public boolean[] judgeIt(TreeNode root) {

        // write code here

        boolean[] isbool = new boolean[2];

        isbool[0] = true;//为空时无法进入循环,因此这里设为true

        ArrayList<Integer> list = new ArrayList();

        inOrder(root, list);

        for (int i = 1; i < list.size(); i++) {//判断是否为升序

            if (list.get(i) <= list.get(i - 1)) {

                isbool[0] = false;

                break;

            } else {

                isbool[0] = true;

            }

        }

        isbool[1] = isCompleteTree(root);

        return isbool;



    }



    public void inOrder(TreeNode root, ArrayList list) {

        //特判

        if (root == null) {

            return;

        }

        //递归调用:对左右子树进行递归的遍历

        inOrder(root.left, list);

        list.add(root.val);

        inOrder(root.right, list);

    }



    public boolean isCompleteTree(TreeNode root) {

        Queue<TreeNode> queue = new LinkedList<TreeNode>();

        queue.offer(root);

        while (queue.peek() != null) {//层序遍历,将子女双全的节点及其子节点出队,

        //当遍历到第一个左子节点为空时结束循环

            TreeNode node = queue.poll();

            queue.offer(node.left);

            queue.offer(node.right);

        }

        //根据定义,当跳出上面的循环后,队列里全为空节点

        while (!queue.isEmpty() && queue.peek() == null) {

            queue.poll();

        }

        return queue.isEmpty();

    }

}

12.最大路径和

www.nowcoder.com/practice/da…

最大贡献值:以该节点为根节点的子树中寻找以该节点为起点的一条路径,使得该路径上的节点值之和最大。

空节点的最大贡献值等于 0。

非空节点的最大贡献值等于节点值与其子节点中的最大贡献值之和(对于叶节点而言,最大贡献值等于节点值

有了每个节点的最大贡献值后,即可求每个节点的最大路径。

/*

 * public class TreeNode {

 *   int val = 0;

 *   TreeNode left = null;

 *   TreeNode right = null;

 * }

 */



public class Solution {

    /**

 *

 *  @param root TreeNode类

 *  @return int整型

 */

 int maxSum = Integer.MIN_VALUE;

    public int maxPathSum (TreeNode root) {

        // write code here

        maxGain(root);

        return maxSum;

    }

    public int maxGain(TreeNode node) {

        if (node == null) {

            return 0;

        }



        // 递归计算左右子节点的最大贡献值

        // 只有在最大贡献值大于 0 时,才会选取对应子节点

        int leftGain = Math.max(maxGain(node.left), 0);

        int rightGain = Math.max(maxGain(node.right), 0);



        // 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值

        //这里贡献值只会为非负数,为0 时表示不选择该节点

        int priceNewpath = node.val + leftGain + rightGain;



        // 更新答案

        maxSum = Math.max(maxSum, priceNewpath);



        // 返回该节点的最大贡献值

        return node.val + Math.max(leftGain, rightGain);

    }

}

13.对称的二叉树

www.nowcoder.com/practice/ff…

/*

public class TreeNode {

    int val = 0;

    TreeNode left = null;

    TreeNode right = null;



    public TreeNode(int val) {

        this.val = val;



    }



}

*/

class Solution {

    //对一个节点的左右节点进行对称判断,然后对他们的子节点在进行递归判断

    public boolean isSymmetrical(TreeNode root) {

        return check(root, root);

    }

    boolean check(TreeNode a, TreeNode b) {

        //如果是对称的,那么会递归到同为空的子节点(叶子节点或者同时缺少对称位的孩子节点),返回true

        if (a == null && b == null) return true;

        //如果中间出现了某个对称位缺失或者值不相同则返回false

        if (a == null || b == null) return false;

        if (a.val != b.val) return false;

        //对称判断的实际为外侧和内侧是否同时对称

        return check(a.left, b.right) && check(a.right, b.left);

    }

}

14.二叉树中和为某一值的路径(一)

代码采用第十题修改版

www.nowcoder.com/practice/50…

import java.util.ArrayList;

import java.util.LinkedList;

 /**

 * public class TreeNode {

 * int val = 0;

 * TreeNode left = null;

 * TreeNode right = null;

 * <p>

 * public TreeNode(int val) {

 * this.val = val;

 * }

 * }

 */

public class Solution {

    public boolean hasPathSum(TreeNode root, int sum) {

        return dfs(root, sum);

    }

    public boolean dfs(TreeNode root, int tar) {

        //叶子节点结束递归

        if (root == null) {

            return false;

        }

        //更新目标值,每放入一个节点,目标值应该相应减去对应节点的值,直到目标值为0

        tar -= root.val;

        //如果目标值减到了0 && 左节点为空 && 右节点为空 证明树已遍历完,此路径为目标路径

        if (tar == 0 && root.left == null && root.right == null) {

            return true;

        }

        // 递归左右子树

        boolean x;

        x=dfs(root.left, tar);

        if(x == true)//这里如果左子树找到路径则提前返回,剪枝且避免x被右子树的覆盖

            return x;

        x=dfs(root.right, tar);

        return x;

    }

}