递归三部曲 做二叉树的题,要走以下三步:
确定单层递归的逻辑 :是根左右(前序遍历)还是左根右(中序遍历)、左右根(后序遍历),又或是层序遍历。
确定递归函数的参数和返回值
确定终止条件 :在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要结束了,所以如果当前遍历的这个节点是空,就要return了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class Solution { public List<Integer> preorderTraversal (TreeNode root) { List<Integer> res = new ArrayList <>(); preorder(root, res); return res; } private void preorder (TreeNode root, List<Integer> res) { if (root == null ) return ; res.add(root.val); preorder(root.left, res); preorder(root.right, res); } public List<Integer> inorderTraversal (TreeNode root) { List<Integer> res = new ArrayList <>(); inorder(root, res); return res; } private void inorder (TreeNode root, List<Integer> res) { if (root == null ) return ; inorder(root.left, res); res.add(root.val); inorder(root.right, res); } public List<Integer> postorderTraversal (TreeNode root) { List<Integer> res = new ArrayList <>(); postorder(root, res); return res; } private void postorder (TreeNode root, List<Integer> res) { if (root == null ) return ; postorder(root.left, res); postorder(root.right, res); res.add(root.val); } }
层序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public List<List<Integer>> levelOrder (TreeNode root) { List<List<Integer>> res = new ArrayList <>(); if (root == null ) return res; Queue<TreeNode> queue = new LinkedList <>(); queue.offer(root); while (!queue.isEmpty()) { int levelSize = queue.size(); List<Integer> levelNodes = new ArrayList <>(); for (int i = 0 ; i < levelSize; i++) { TreeNode node = queue.poll(); levelNodes.add(node.val); if (node.left != null ) queue.offer(node.left); if (node.right != null ) queue.offer(node.right); } res.add(levelNodes); } return res; } }
例题 给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
递归三部曲:第一步: 我们先想用那种递归顺序呢,题目说求二叉树深度,其实就是求二叉树的高度。
高度怎么求?当然是root的高度等于左子树的高度和右子树的高度之中的最大值加一了。
那么哪种遍历顺序可以很方便的实现Math.max(leftHeight, rightHeight) + 1;呢?很明显是后序遍历。
第二步: 返回值肯定要返回最大值,所以是int,参数只需传入root节点,能够找到其左子树右子树正常遍历整棵树就行。
第三步: 当节点为null时,我们应该return什么?注意应该是0,为null的节点是叶子节点的孩子,他们并不属于树的高度统计范围,高度为0。
完整代码:
1 2 3 4 5 6 7 8 9 10 class Solution { public int maxDepth (TreeNode root) { if (root == null ) return 0 ; int leftHeight = maxDepth(root.left); int rightHeight = maxDepth(root.right); return Math.max(leftHeight, rightHeight) + 1 ; } }
构造二叉树 这里以前序遍历和中序遍历为例,因为前序遍历是根左右顺序,所以第一个即使根节点,因为中序遍历是左根右顺序,那么就可以根据根节点,分出左右子树,同理,此时可以拿出由中序遍历得出的左子树,将其看为一组新的要我们根据前序遍历,中序遍历构造的二叉树。
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历 , inorder 是同一棵树的中序遍历 ,请构造二叉树并返回其根节点。
代码来自leetcode官方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Solution { private Map<Integer, Integer> indexMap; public TreeNode myBuildTree (int [] preorder, int [] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) { if (preorder_left > preorder_right) { return null ; } int preorder_root = preorder_left; int inorder_root = indexMap.get(preorder[preorder_root]); TreeNode root = new TreeNode (preorder[preorder_root]); int size_left_subtree = inorder_root - inorder_left; root.left = myBuildTree(preorder, inorder, preorder_left + 1 , preorder_left + size_left_subtree, inorder_left, inorder_root - 1 ); root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1 , preorder_right, inorder_root + 1 , inorder_right); return root; } public TreeNode buildTree (int [] preorder, int [] inorder) { int n = preorder.length; indexMap = new HashMap <Integer, Integer>(); for (int i = 0 ; i < n; i++) { indexMap.put(inorder[i], i); } return myBuildTree(preorder, inorder, 0 , n - 1 , 0 , n - 1 ); } }