[关闭]
@ysongzybl 2015-05-12T17:52:02.000000Z 字数 7867 阅读 1443

Summary of Binary Tree: (Build)

interview


0. Definitions of Binary Tree Node and Segment Tree Node

  1. public class TreeNode{
  2. int val;
  3. TreeNode left, right;
  4. TreeNode(int i) {
  5. val = i;
  6. left = right = null;
  7. }
  8. }
  9. public class SegmentTreeNode{
  10. int start, end, count;
  11. SegmentTreeNode left, right;
  12. SegmentTreeNode(int start, int end){
  13. this.start = start;
  14. this.end = end;
  15. left = right = null;
  16. }
  17. }

1. Convert Sorted Array to BST

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

Example : 1,3,5,6,7,8,9

  1. 6
  2. / \
  3. 3 8
  4. / \ / \
  5. 1 5 7 9

Idea:
Each time pick the middle element in the array, make it as the root:
1. its left child is the middle element of the left subarray
2. its right child is the middle element of the right subarray

  1. public TreeNode build(int[] nums, int low, int high){
  2. if(low>high) return null;
  3. int mid = (low+high)/2;
  4. int val = nums[mid];
  5. TreeNode root = new TreeNode(val);
  6. root.left = build(nums, low, mid-1);
  7. root.right = build(nums, mid+1, high);
  8. return root;
  9. }
  10. public TreeNode sortedArrayToBST(int[] nums) {
  11. int n = nums.length;
  12. if(n==0) return null;
  13. return build(nums, 0, n-1);
  14. }

2. Convert Sorted Linked List to BST

Given a singly linked list where elements are s orted in ascending order, convert it to a height balanced BST.

Example : 1->3->5->6->7->null

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

Idea: Create Root with Bottom-up Recursion
KEY: make list head global (if Cpp, just pass by a reference to the head pointer)
1. Make left child node using the middle of left half list
2. Make root node using the middle of list
3. Make right child node using the middle of the right half list

  1. public int getListLength(ListNode head){
  2. if(head==null) return 0;
  3. return 1+getListLength(head.next);
  4. }
  5. public ListNode curhead; // important!
  6. public TreeNode build(int len){
  7. if(curhead==null || len<=0) return null;
  8. TreeNode left = build(len/2);
  9. TreeNode root = new TreeNode(curhead.val);
  10. root.left = left;
  11. curhead = curhead.next;
  12. TreeNode right = build(len-len/2-1);
  13. root.right = right;
  14. return root;
  15. }
  16. public TreeNode sortedListToBST(ListNode head) {
  17. int len = getListLength(head);
  18. curhead = head;
  19. return build(len);
  20. }

3. Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place.

Example:

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

Output

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

Idea:
For each node
1. flatten right subtree to list
2. flatten left subtree

if left subtree is null, then just return the root
else 
    1) append the flattened right subtree to the *tail* of flattened left subtree
    2) attach to the right child of the node while set the left child of the node to null    
  1. public TreeNode build(TreeNode node){
  2. if(node==null) return null;
  3. TreeNode right = build(node.right);
  4. TreeNode left = build(node.left);
  5. if(left != null){
  6. TreeNode left_tail = left;
  7. while(left_tail !=null && left_tail.right!=null){
  8. left_tail = left_tail.right;
  9. }
  10. left_tail.right = right;
  11. node.left = null;
  12. node.right = left;
  13. }
  14. return node;
  15. }
  16. public void flatten(TreeNode root){
  17. root = build(root);
  18. }

4. Construct Binary Tree from Preorder and Inorder Traversal

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

Example: Given in-order [1,2,3] and pre-order [2,1,3], return a tree:

  1. 2
  2. / \
  3. 1 3

Idea:
1. Locate the root: for the sequence from preorder traversal, the root always shows at the first
2. Split the inorder sequence into two halves: left subtree and right subtree
3. For each subtree sequence, we can tell the size of subtree
4. Use the determined subtree size in the preorder sequence (exclude the root), find the left subtree root and the right subtree root, and repeat from step 1

  1. public TreeNode build(int[] preorder, int[] inorder, int prestart, int preend, int instart, int inend, HashMap<Integer, Integer> inorder_pos){
  2. if(prestart>preend || instart>inend) return null;
  3. int val = preorder[prestart];
  4. TreeNode root = new TreeNode(val);
  5. int pos = inorder_pos.get(val);
  6. int leftsize = pos-instart;
  7. int rightsize = inend-pos;
  8. root.left = build(preorder, inorder, prestart+1, prestart+leftsize, instart, pos-1, inorder_pos);
  9. root.right = build(preorder, inorder, preend-rightsize+1, preend, pos+1, inend, inorder_pos);
  10. return root;
  11. }
  12. public TreeNode buildTree(int[] preorder, int [] inorder){
  13. int n = preorder.length;
  14. if(n==0) return null;
  15. HashMap<Integer, Integer> inorder_pos = new HashMap<Integer, Integer>();
  16. for(int i=0; i<n; i++){
  17. inorder_pos.put(inorder[i],i);
  18. }
  19. return build(preorder, inorder, 0, n-1, 0, n-1, inorder_pos);
  20. }

5. Unique Binary Trees II

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

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

  1. 1 3 3 2 1
  2. \ / / / \ \
  3. 3 2 1 1 3 2
  4. / / \ \
  5. 2 1 2 3

Idea:
Given a number n, for each i[1,n], it can be a tree root. For a root with value i:
1. its left subtree node could be any number j[1,i1] (i1 possible choices)
2. its right subtree node could be any number k[i+1,n] (ni possible choices)
Note as we increase variable i, we need a terminate condition: when i<1 or i>n, let it corresponds to a null node.

Using bottom-up construction, for node i:
construct a set (L) of all possible nodes belonging to its left subtree,
construct a set (R) of all possible nodes belonging to its right subtree,
that is, if we choose a node aL as the left child of node i, then, we have R.size() choices to select a right child for the node i

  1. public void build(List<TreeNode> roots, int start, int end){
  2. if(start>end){
  3. roots.add(null);
  4. return;
  5. }
  6. for(int i=start; i<=end; i++){ // Note: not from 1 to n
  7. List<TreeNode> L = new ArrayList<TreeNode>();
  8. build(L, start, i-1);
  9. List<TreeNode> R = new ArrayList<TreeNode>();
  10. build(R, i+1, end);
  11. for(TreeNode a : L){
  12. for(TreeNode b : R){
  13. TreeNode root = new TreeNode(i);
  14. root.left = a;
  15. root.right = b;
  16. roots.add(root);
  17. }
  18. }
  19. }
  20. }
  21. public List<TreeNode> generateTrees(int n) {
  22. List<TreeNode> res = new ArrayList<TreeNode>();
  23. build(res, 1, n); // Note: start from 1 not 0
  24. return res;
  25. }

6. Max Tree

Given an integer array with no duplicates. A max tree building on this array is defined as follow:

The root is the maximum number in the array
The left subtree and right subtree are the max trees of the subarray divided by the root number.
Construct the max tree by the given array.

Example : [2, 5, 6, 0, 3, 1]

  1. 6
  2. / \
  3. 5 3
  4. / / \
  5. 2 0 1

Idea:
Sequentially create tree node when iterate the input array (one-pass)
KEY: maintaining/updating the root node: R
For i in the array, create a node ni
1. if R is null, make ni the root
2. if ni value is greater than the root's value, then make ni the root, attach previous root as its left subtree
3. otherwise, insert ni to a proper position in current root's right subtree, by recursively executing step 1 to 3 with R.right as root

  1. public TreeNode insert(TreeNode root, int cur){
  2. TreeNode node = new TreeNode(cur);
  3. if(root==null) {
  4. return node;
  5. }
  6. if(node.val>root.val){
  7. node.left = root;
  8. return node;
  9. }
  10. // keep on looking up the right subtree of root and update the right child
  11. root.right = insert(root.right, cur);
  12. return root;
  13. }
  14. public TreeNode maxTree(int[] A) {
  15. int n = A.length;
  16. if(n==0) return null;
  17. TreeNode root = new TreeNode(A[0]);
  18. for(int i=1; i<n; i++){
  19. int cur = A[i];
  20. if(cur > root.val){
  21. TreeNode node = new TreeNode(cur);
  22. node.left = root;
  23. root = node;
  24. }else{
  25. root.right = insert(root.right, cur);
  26. }
  27. }
  28. return root;
  29. }

7. Segment Tree

The structure of Segment Tree is a binary tree which each node has two attributes start and end denote an segment/interval.

start and end are both integers, they should be assigned in following rules:

The root's start and end is given by build method.
The left child of node A has start=A.start, end=(A.start + A.end) / 2.
The right child of node A has start=(A.start + A.end) / 2 + 1, end=A.end.
if start equals to end, there will be no children for this node.

Implement a build method with two parameters start and end, so that we can create a corresponding segment tree with every node has the correct start and end value, return the root of this segment tree.

Exmaple : Given start = 0, end = 4

  1. [0, 4]
  2. / \
  3. [0,2] [3,4]
  4. / \ / \
  5. [0,1] [2,2] [3,3] [4,4]
  6. / \
  7. [0,0][1,1]
  1. // Recurisve version
  2. public SegmentTreeNode build(int start, int end){
  3. if(start > end) return null;
  4. SegmentTreeNode root = new SegmentTreeNode(start, end);
  5. if(start == end) return root;
  6. int mid = (start+end)/2;
  7. root.left = build(start, mid);
  8. root.right= build(mid+1, end);
  9. return root;
  10. }
  11. // Iterative version
  12. public SegmentTreeNode build(int start, int end) {
  13. if(start > end) return null;
  14. SegmentTreeNode root = new SegmentTreeNode(start, end);
  15. if(start == end) return root;
  16. Queue<SegmentTreeNode> Q = new LinkedList<SegmentTreeNode>();
  17. Q.add(root);
  18. while(!Q.isEmpty()){
  19. SegmentTreeNode cur = Q.poll();
  20. if(cur.start != cur.end){
  21. SegmentTreeNode left = new SegmentTreeNode(cur.start, (cur.start+cur.end)/2);
  22. cur.left = left;
  23. SegmentTreeNode right = new SegmentTreeNode((cur.start+cur.end)/2+1, cur.end);
  24. cur.right = right;
  25. Q.add(cur.left);
  26. Q.add(cur.right);
  27. }
  28. }
  29. return root;
  30. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注