LeetCode 二叉树 题目分类汇总

目录

简书的 markdown 都不支持 [TOC] 语法……我就不贴目录了。下面按照类别,列出了29道关于二叉树的题目。认真看会发现,其实题目核心思想都是DFS(如果使用的话),并且题目的类型并不多。

说明

二叉树的题目,主要有一下几种:

  1. 前中后序遍历、根据前序遍历和中序遍历构造二叉树、根据中序遍历和后序遍历构造二叉树;
  2. BST:查找第k大的数
  3. LCA:最近公共祖先
  4. 层序遍历
  5. 扩展树
  6. 序列化、反序列化二叉树

大部分题目使用DFS会更简洁。这篇文章并没有区分节点结点,因为我也不知道用哪个……

题目并不在于多,我把LeetCode上部分相似的题目列出来,大家通过对比观察相似题目,就能够触类旁通。其实90%的题目都是差不多的,只是换了不同的问法而已。

题目

144. Binary Tree Preorder Traversal

Given a binary tree, return the preorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},

   1
    \
     2
    /
   3

return [1,2,3].

Note: Recursive solution is trivial, could you do it iteratively?

递归

public class Solution {
    
    public void robot(TreeNode p, List<Integer> ans) {
        if(p == null) return;
        // 中左右
        ans.add(p.val);
        robot(p.left, ans);
        robot(p.right, ans);
    }
    
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<Integer>();
        robot(root, ans);
        return ans;
    }
}

非递归

拿出并访问一个结点,将左右结点放入。

public class Solution {
    
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<Integer>();
        
        List<TreeNode> vector = new ArrayList<TreeNode>();
        vector.add(root);
        while(vector.size() != 0){
            TreeNode r = vector.get(vector.size() - 1);
            vector.remove(vector.size() - 1);
            if(r != null) {
                ans.add(r.val);
                vector.add(r.right);
                vector.add(r.left);
            }
        }
        
        return ans;
    }
}

94. Binary Tree Inorder Traversal

Given a binary tree, return the inorder traversal of its nodes' values.

For example:
Given binary tree [1,null,2,3],

   1
    \
     2
    /
   3

return [1,3,2].

Note: Recursive solution is trivial, could you do it iteratively?

递归

public class Solution {
    
    public void robot(TreeNode p, List<Integer> ans) {
        if(p == null) return;
        // 左中右
        robot(p.left, ans);
        ans.add(p.val);
        robot(p.right, ans);
    }
    
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<Integer>();
        robot(root, ans);
        return ans;
    }
}

非递归

public class Solution {
    
    public List<Integer> inorderTraversal(TreeNode r) {
        List<Integer> ans = new ArrayList<Integer>();
        
        List<TreeNode> vector = new ArrayList<TreeNode>();
        while(vector.size() != 0 || r != null){
            
            // 一直放入左儿子(左)
            while(r != null) {
                vector.add(r);
                r = r.left;
            }
            
            // 访问当前元素(中),把右儿子入栈(右)
            if(vector.size() != 0) {
                r = vector.get(vector.size() - 1);
                vector.remove(vector.size() - 1);
                ans.add(r.val);
                r = r.right;
            }
        }
        
        return ans;
    }
}

145. Binary Tree Postorder Traversal

Given a binary tree, return the postorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},

   1
    \
     2
    /
   3

return [3,2,1].

Note: Recursive solution is trivial, could you do it iteratively?

递归

public class Solution {
     public void robot(TreeNode p, List<Integer> ans) {
        if(p == null) return;
        // 左右中
        robot(p.left, ans);
        robot(p.right, ans);
        ans.add(p.val);
    }
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<Integer>();
        robot(root, ans);
        return ans;
    }
}

非递归

后序遍历的非递归写法有些麻烦,因为结点第一次访问时并不打印,而是在第二次遍历时才打印。所以需要一个变量来标记该结点是否访问过。

public class Solution {
    
    public static class StackNode {
        TreeNode r;
        boolean isFirst;
        StackNode(TreeNode r, boolean isFirst) {
            this.r = r;
            this.isFirst = isFirst;
        }
    }
    public List<Integer> postorderTraversal(TreeNode r) {
        List<Integer> ans = new ArrayList<Integer>();
        
        List<StackNode> vector = new ArrayList<StackNode>();
        StackNode node;
        while(vector.size() != 0 || r != null){
            
            // 一直放入左儿子(左)
            while(r != null) {
                node = new StackNode(r, true);
                vector.add(node);
                r = r.left;
            }
            
            // 把右儿子入栈(右),访问当前元素(中)
            if(vector.size() != 0) {
                node = vector.get(vector.size() - 1);
                vector.remove(vector.size() - 1);
                
                // 首次访问,再次入栈,并置状态
                if(node.isFirst) {
                    node.isFirst = false;
                    vector.add(node);
                    r = node.r.right;
                } else {
                    ans.add(node.r.val);
                    r = null;
                }
            }
        }
        
        return ans;
    }
}

102. Binary Tree Level Order Traversal

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

For example:
Given binary tree [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

return its level order traversal as:

[
  [3],
  [9,20],
  [15,7]
]

思路:ans的第k个元素,存储第k层的答案,在遍历的过程中记录答案。原型就是前序遍历

public class Solution {
    
    public void robot(List<List<Integer>> ans, TreeNode root, int height) {
        if(root == null) return;
        if(height >= ans.size()){
            ans.add(new ArrayList<Integer>());
        }
        
        ans.get(height).add(root.val);
        robot(ans, root.left, height + 1);
        robot(ans, root.right, height + 1);
    }
    
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        robot(ans, root, 0);
        return ans;
    }
}

103. Binary Tree Zigzag Level Order Traversal

Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).

For example:
Given binary tree [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

return its zigzag level order traversal as:

[
  [3],
  [20,9],
  [15,7]
]

思路:和上一题是一样的,要么在遍历的过程中,将偶数层反转;要么在结束的时候,将偶数层反转。

public class Solution {
    public void robot(List<List<Integer>> ans, TreeNode root, int height) {
        if(root == null) return;
        if(height >= ans.size()){
            ans.add(new ArrayList<Integer>());
        }
        
        ans.get(height).add(root.val);
        robot(ans, root.left, height + 1);
        robot(ans, root.right, height + 1);
    }
    
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        robot(ans, root, 0);
        for(int i = 0; i < ans.size(); i++) {
            if(i % 2 != 0) {
                Collections.reverse(ans.get(i));
            }
        }
        return ans;
    }
}

199. Binary Tree Right Side View

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

For example:
Given the following binary tree,

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

You should return [1, 3, 4].

思路:这道题其实也是层序遍历,和前两道题一模一样,只不过要记录的不是每层所有的结果,只需要记录每层的最后一个结果!

public class Solution {
    
    public void robot(TreeNode root, List<Integer> ans, int height) {
        if(root == null) return;
        if(ans.size() <= height) {
            ans.add(0);
        }
        ans.set(height, root.val);
        robot(root.left, ans, height + 1);
        robot(root.right, ans, height + 1);
    }
    
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> ans = new ArrayList<Integer>();
        robot(root, ans, 0);
        return ans;
    }
}

105. Construct Binary Tree from Preorder and Inorder Traversal

Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

思路:论坛上的一个答案

The basic idea is here:

  • Say we have 2 arrays, PRE and IN.
  • Preorder traversing implies that PRE[0] is the root node.
  • Then we can find this PRE[0] in IN, say it's IN[5].
  • Now we know that IN[5] is root, so we know that IN[0] - IN[4] is on the left side, IN[6] to the end is on the right side.
  • Recursively doing this on subarrays, we can build a tree out of it :)
public class Solution {
    
    TreeNode build(int preStart, int inStart, int inEnd, int[] pre, int[] in) {
        if(preStart >= pre.length || inStart > inEnd) {
            return null;
        }
        TreeNode root = new TreeNode(pre[preStart]);
        
        int inIndex = 0;
        for(int i = inStart; i <= inEnd; i++) {
            if(in[i] == root.val) {
                inIndex = i;
                break;
            }
        }
        
        root.left = build(preStart + 1, inStart, inIndex - 1, pre, in);
        root.right = build(preStart + inIndex - inStart + 1, inIndex + 1, inEnd, pre, in);
        return root;
    }
    
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        TreeNode root = build(0, 0, inorder.length - 1, preorder, inorder);
        return root;
    }
}

106. Construct Binary Tree from Inorder and Postorder Traversal

Given inorder and postorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

public class Solution {
    
    public TreeNode robot(int poStart, int poEnd, int inStart, int inEnd, int[] in, int[] po) {
        if(poStart > poEnd) {
            return null;
        }
        
        TreeNode root = new TreeNode(po[poEnd]);
        int index = 0;
        for(int i = inStart; i <= inEnd; i++) {
            if(in[i] == root.val) {
                index = i;
                break;
            }
        }
        
        root.left = robot(poStart, poStart + index - inStart - 1 , inStart, index - 1, in, po);
        root.right = robot(poEnd - inEnd + index, poEnd - 1, index + 1, inEnd, in, po);
        
        return root;
    }
    
    public TreeNode buildTree(int[] in, int[] po) {
        TreeNode root = robot(0, po.length - 1, 0, in.length - 1, in, po);
        return root;
    }
}

95. Unique Binary Search Trees II

Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n.

For example,
Given n = 3, your program should return all 5 unique BST's shown below.

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

思路:首先确定根节点,然后确定左子树和右子树。注意同一个数作为根节点时,可能有多个不同的子树。

public class Solution {
    
    public List<TreeNode> robot(int start, int end) {
        List<TreeNode> ans = new ArrayList<TreeNode>();
        
        if(start > end) {
            ans.add(null);
            return ans;
        }
        
        if(start == end) {
            ans.add(new TreeNode(start));
            return ans;
        }
        
        for(int i = start; i <= end; i++) {
            List<TreeNode> leftList = robot(start, i - 1);
            List<TreeNode> rightList = robot(i + 1, end);
            for(TreeNode left : leftList) {
                for(TreeNode right : rightList) {
                    TreeNode root = new TreeNode(i);
                    root.left = left;
                    root.right = right;
                    ans.add(root);
                }
            }    
        }
        
        return ans;
    }
    
    public List<TreeNode> generateTrees(int n) {
        if(n == 0) return new ArrayList<TreeNode>();
        return robot(1, n);
    }
}

96. Unique Binary Search Trees

Given n, how many structurally unique BST's (binary search trees) that store values 1...n?

For example,
Given n = 3, there are a total of 5 unique BST's.

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

思路:设f(n)代表构造出的树的个数。那么:

f(n) = f(n-1)f(0) + f(n-2)f(1) + ... + f(0)f(n-1)
public class Solution {
    public int numTrees(int n) {
        if(n <= 0) return 0;
        int[] dp = new int[n + 1];
        dp[0] = 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];
    }
}

98. Validate Binary Search Tree

Given a binary tree, determine if it is a valid binary search tree (BST).

Assume a BST is defined as follows:

The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
Example 1:

    2
   / \
  1   3

Binary tree [2,1,3], return true.
Example 2:

    1
   / \
  2   3

Binary tree [1,2,3], return false.

public class Solution {
    
    public boolean robot(TreeNode root, long min, long max) {
        if(root == null) return true;
        if(root.val >= max || root.val <= min) return false;
        return robot(root.left, min, root.val) && robot(root.right, root.val, max);
    }
    
    public boolean isValidBST(TreeNode root) {
        return robot(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }
}

100. Same Tree

Given two binary trees, write a function to check if they are equal or not.

Two binary trees are considered equal if they are structurally identical and the nodes have the same value.

public class Solution {
    
    public boolean robot(TreeNode p, TreeNode q) {
        if(p == null && q == null) {
            return true;
        }
        if(p != null && q != null && p.val == q.val) {
            return robot(p.left, q.left) && robot(p.right, q.right);
        }
        return false;
    }
    
    public boolean isSameTree(TreeNode p, TreeNode q) {
        return robot(p, q);
    }
}

101. Symmetric Tree

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

For example, this binary tree [1,2,2,3,4,4,3] is symmetric:

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

But the following [1,2,2,null,3,null,3] is not:

    1
   / \
  2   2
   \   \
   3    3

Note:
Bonus points if you could solve it both recursively and iteratively.

public class Solution {
    
    public boolean robot(TreeNode p, TreeNode q) {
        if(p == null && q == null) {
            return true;
        }
        if(p != null && q != null && p.val == q.val) {
            return robot(p.left, q.right) && robot(p.right, q.left);
        }
        return false;
    }
    
    public boolean isSymmetric(TreeNode root) {
        if(root == null) return true;
        return robot(root.left, root.right);
    }
}

104. Maximum Depth of Binary Tree

Given a binary tree, find its maximum depth.

The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

public class Solution {
    
    public int robot(TreeNode root, int depth) {
        if(root == null) return depth;
        return Math.max(robot(root.left, depth + 1), robot(root.right, depth + 1));
    }
    
    public int maxDepth(TreeNode root) {
        return robot(root, 0);
    }
}

110. Balanced Binary Tree

Given a binary tree, determine if it is height-balanced.

For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.

public class Solution {
    
    public int depth(TreeNode root) {
        if(root == null) return 0;
        return Math.max(depth(root.left), depth(root.right)) + 1;
    }
    
    public boolean isBalanced(TreeNode root) {
        if(root == null) return true;
        
        int left = depth(root.left);
        int right = depth(root.right);
        
        return Math.abs(left - right) <= 1 && isBalanced(root.left) && isBalanced(root.right);
    }
}

111. Minimum Depth of Binary Tree

Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

public class Solution {
    
    public int minDepth(TreeNode root) {
        if(root == null) return 0;
        int left = minDepth(root.left);
        int right = minDepth(root.right);
        return (left == 0 || right == 0) ? (left + right + 1) : Math.min(left, right) + 1;
    }
}

112. Path Sum

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

For example:
Given the below binary tree and sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \      \
    7    2      1

return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

public class Solution {

    public boolean hasPathSum(TreeNode root, int sum) {
        if(root == null) return false;
        int left = sum - root.val;
        if(root.left == null && root.right == null && left == 0) {
            return true;
        }
        return hasPathSum(root.left, left) || hasPathSum(root.right, left);
    }
}

113. Path Sum II

Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.

For example:
Given the below binary tree and sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \    / \
    7    2  5   1

return

[
   [5,4,11,2],
   [5,8,4,5]
]

思路:和上一道题是一样的,只不过这次需要保存结果。

public class Solution {
    
    public void robot(TreeNode root, int sum, List<List<Integer>> ans, List<Integer> tmp) {
        if(root == null) return;
        if(root.left == null && root.right == null && sum - root.val == 0) {
            tmp.add(root.val);
            ans.add(new ArrayList(tmp));
            tmp.remove(tmp.size() - 1);
            return;
        }
        tmp.add(root.val);
        robot(root.left, sum - root.val, ans, tmp);
        robot(root.right, sum - root.val, ans, tmp);
        tmp.remove(tmp.size() - 1);
    }
    
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        List<Integer> tmp = new ArrayList<Integer>();
        robot(root, sum, ans, tmp);
        return ans;
    }
}

129. Sum Root to Leaf Numbers

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.

An example is the root-to-leaf path 1->2->3 which represents the number 123.

Find the total sum of all root-to-leaf numbers.

For example,

    1
   / \
  2   3

The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.

Return the sum = 12 + 13 = 25.

public class Solution {
    
    public int robot(TreeNode root, int sum) {
        if(root == null) return 0;
        if(root.left == null && root.right == null) {
            return sum * 10 + root.val;
        }
        return robot(root.left, sum * 10 + root.val) + robot(root.right, sum * 10 + root.val);
    }

    public int sumNumbers(TreeNode root) {
        return robot(root, 0);
    }
}

257. Binary Tree Paths

Given a binary tree, return all root-to-leaf paths.

For example, given the following binary tree:

   1
 /   \
2     3
 \
  5

All root-to-leaf paths are:

["1->2->5", "1->3"]

思路:这个题和上面的题是一样的,只不过上面的题求根节点到叶子节点的和,而这道题是把路径用字符串表示出来。

public class Solution {
    
    public void robot(TreeNode root, String path, List<String> ans) {
        if(root.left == null && root.right == null) {
            ans.add(path + root.val);
            return;
        }
        if(root.left != null) robot(root.left, path + root.val + "->", ans);
        if(root.right != null) robot(root.right, path + root.val + "->", ans);
    }
    
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> ans = new ArrayList<String>();
        if(root != null) {
            robot(root, "", ans);
        }
        return ans;
    }
}

108. Convert Sorted Array to Binary Search Tree

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.

public class Solution {
    
    public TreeNode robot(int[] nums, int start, int end) {
        if(start > end) return null;
        int mid = (start + end) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        // 已经是排序数组,所以只要找中点即可
        root.left = robot(nums, start, mid - 1);
        root.right = robot(nums, mid + 1, end);
        return root;
    }
    
    public TreeNode sortedArrayToBST(int[] nums) {
        // 二分,才会「高度平衡」
        if(nums.length == 0) return null;
        return robot(nums, 0, nums.length - 1);
    }
}

116. Populating Next Right Pointers in Each Node

Given a binary tree

struct TreeLinkNode {
  TreeLinkNode *left;
  TreeLinkNode *right;
  TreeLinkNode *next;
}

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Note:

You may only use constant extra space.
You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).
For example,
Given the following perfect binary tree,

     1
   /  \
  2    3
 / \  / \
4  5  6  7

After calling your function, the tree should look like:

     1 -> NULL
   /  \
  2 -> 3 -> NULL
 / \  / \
4->5->6->7 -> NULL
public class Solution {
    
    public void connect(TreeLinkNode root) {
       if(root == null) return;
       if(root.left != null) {
           root.left.next = root.right;
           if(root.right != null && root.next != null) {
               root.right.next = root.next.left;
           }
       }
       
       connect(root.left);
       connect(root.right);
    }
}

222. Count Complete Tree Nodes

Given a complete binary tree, count the number of nodes.

Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

思路:相当于二分查找,并不需要挨个遍历每个节点。只要从某一节点开始,到左叶子结点和到右叶子结点的长度相同,就可以利用性质计算出结点个数。

public class Solution {
    public int countNodes(TreeNode root) {
        if(root == null) return 0;
        
        int left = leftHeight(root);
        int right = rightHeight(root);
        
        if(left == right) {
            return (1 << left) - 1;
        }
        
        return 1 + countNodes(root.left) + countNodes(root.right);
    }
    
    public int leftHeight(TreeNode root) {
        int depth = 0;
        while(root != null) {
            root = root.left;
            depth++;
        }
        return depth;
    }
    
    public int rightHeight(TreeNode root) {
        int depth = 0;
        while(root != null) {
            root = root.right;
            depth++;
        }
        return depth;
    }
}

226. Invert Binary Tree

Invert a binary tree.

     4
   /   \
  2     7
 / \   / \
1   3 6   9

to

     4
   /   \
  7     2
 / \   / \
9   6 3   1
public class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) return root;
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

230. Kth Smallest Element in a BST

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.

Note:
You may assume k is always valid, 1 ? k ? BST's total elements.

Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?

思路:利用BST的性质,前序遍历的第k个数,即为第k大的数。

public class Solution {
    
    private static int number = 0; // 最终结果
    private static int count = 0;
    
    public void robot(TreeNode r) {
        if(r.left != null) robot(r.left);
        
        count--;
        if(count == 0) {
            number = r.val;
            return;
        }
        
        if(r.right != null) robot(r.right);
    }
    
    // 中序遍历,第k个数
    public int kthSmallest(TreeNode root, int k) {
        count = k;
        robot(root);
        return number;
    }
}

235. Lowest Common Ancestor of a Binary Search Tree

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

        _______6______
       /              \
    ___2__          ___8__
   /      \        /      \
   0      _4       7       9
         /  \
         3   5

For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.

思路:利用BST的性质,LCA是最后一个值介于两个节点之间的节点。

public class Solution {
    public static TreeNode ans = null;
    
    public void robot(TreeNode root, int min, int max) {
        if(root == null) return;
        robot(root.left, min, max);
        if(root.val >= min && root.val <= max) {
            ans = root;
            return;
        }
        robot(root.right, min, max);
    }
    
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 中序遍历,找介于p和q之间的node
        if(root == null || p == null || q == null) return null;
        int min = Math.min(p.val, q.val);
        int max = Math.max(p.val, q.val);
        robot(root, min, max);
        return ans;
    }
}

236. Lowest Common Ancestor of a Binary Tree

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

        _______3______
       /              \
    ___5__          ___1__
   /      \        /      \
   6      _2       0       8
         /  \
         7   4

For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

思路:这道题比上一道题更进一步,去掉了BST的特殊条件。可以分为两种情况:

  • 左右结点并不互为父子节点
  • 左右结点互为父子节点
public 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) return root;
        return left == null ? right : left;
    }
}

297. Serialize and Deserialize Binary Tree

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.

For example, you may serialize the following tree

    1
   / \
  2   3
     / \
    4   5

as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        robot(root, sb);
        return sb.toString();
    }
    
    public void robot(TreeNode root, StringBuilder sb) {
        if(root == null) {
            sb.append("X").append(",");
        } else {
            sb.append(root.val + "").append(",");
            robot(root.left, sb);
            robot(root.right, sb);
        }
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        Deque<String> nodes = new LinkedList<>();
        nodes.addAll(Arrays.asList(data.split(",")));
        return buildTree(nodes);
    }
    
    public TreeNode buildTree(Deque<String> nodes) {
        String val = nodes.remove();
        if(val.equals("X")) {
            return null;
        } else {
            TreeNode root = new TreeNode(Integer.valueOf(val));
            root.left = buildTree(nodes);
            root.right = buildTree(nodes);
            return root;
        }
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

337. House Robber III

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.

Example 1:

     3
    / \
   2   3
    \   \ 
     3   1

Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
Example 2:

     3
    / \
   4   5
  / \   \ 
 1   3   1

Maximum amount of money the thief can rob = 4 + 5 = 9.

思路:实际上是动态规划,当前结点分为两种情况:

  • 抢该结点,那么子节点就不能抢;
  • 不抢该结点,那么子节点可以抢,也可以不抢。
public class Solution {
    
    public int rob(TreeNode root) {
        if(root == null) return 0;
        return Math.max(robIn(root), robEx(root));
    }
    
    public int robIn(TreeNode root) {
        if(root == null) return 0;
        return robEx(root.left) + robEx(root.right) + root.val;
    }
    
    public int robEx(TreeNode root) {
        if(root == null) return 0;
        return rob(root.left) + rob(root.right);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,719评论 0 33
  • 第一章 校园里的小孩 四月的一个傍晚,夕阳西下,天边的晚霞像是小女孩害羞的脸庞,略带红晕。天朗气清,和风徐徐。 王...
    颂亦阅读 447评论 0 2
  • 己所不欲勿施于人 尊重你,是希望你也能尊重我 宽容你,是为了让我自己好过 忍让你,是让我变得不那么斤斤计较 其实,...
    笛笳阅读 242评论 0 0
  • 一打开电脑或手机,全部都是各种娱乐星闻,真是够了。谁离婚了,谁进去了,谁求婚了,世界上似乎只有这些人一样,关注点难...
    泽阳9阅读 283评论 0 0