LeetCode之Tree題目彙總

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.


判斷二叉樹是否平衡,規則如下:

左子樹深度和右子樹深度相差不大於1

核心代碼:

        return Math.abs(height(root.left) - height(root.right)) <= 1
                && isBalanced(root.left) && isBalanced(root.right);
    public boolean isBalanced(TreeNode root) {

        if (root == null) {
            return true;
        }

        return Math.abs(height(root.left) - height(root.right)) <= 1
                && isBalanced(root.left) && isBalanced(root.right);

    }

    int height(TreeNode node) {

        if (node == null) {
            return 0;
        }

        return Math.max(height(node.left), height(node.right)) + 1;
    }

Binary Tree Inorder Traversal

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

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

   1
    \
     2
    /
   3

return [1,3,2].

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

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


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

    public List<Integer> inorderTraversal(TreeNode root) {

        rt.clear();
        inorder(root);
        return rt;
    }

    void inorder(TreeNode node) {

        if (node == null) {
            return;
        }

        inorder(node.left);
        rt.add(node.val);
        inorder(node.right);
    }

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 List<Integer> preorderTraversal(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

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

        while (p != null || !stack.empty()) {

            while (p != null) {
                rt.add(p.val);
                stack.push(p);
                p = p.left;
            }

            if (!stack.empty()) {
                p = stack.pop();
                p = p.right;
            }
        }

        return rt;
    }

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 PostTreeNode {
        TreeNode node;
        boolean first;
    }

    public List<Integer> postorderTraversal(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

        Stack<PostTreeNode> stack = new Stack<PostTreeNode>();
        TreeNode p = root;
        PostTreeNode t;

        while (p != null || !stack.empty()) {

            while (p != null) {

                // 新建一個結點,這個結點包含一個布爾值first
                // 用來判斷是否是第一次入棧
                PostTreeNode post = new PostTreeNode();
                post.node = p;
                post.first = true;
                stack.push(post);
                p = p.left;
            }

            if (!stack.empty()) {

                t = stack.pop();

                // 如果結點第一次出棧,再次入棧,將first置爲false
                if (t.first == true) {
                    t.first = false;
                    stack.push(t);
                    p = t.node.right;
                } else {
                    rt.add(t.node.val);
                    p = null;
                }
            }
        }

        return rt;
    }

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,#,#,15,7},

    3
   / \
  9  20
    /  \
   15   7

return its level order traversal as:

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

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


1. 通過統計每一行的結點數

定義兩個變量,toBePrinted和nextLevel。

toBePrinted:當前待打印結點的數量 
nextLevel:下一層的結點數量

通過Deque來進行統計。


2. 插入特殊結點

參考自:Binary Tree Level Order Traversal

通過插入特殊結點,來判斷一層是否結束。這樣做的好處是不用統計每一層結點數目。僞代碼如下:

a queue stores [step0, step1, step2, ...]

queue.add(first step)

while queue is not empty

  current_step = queue.poll()

  // do something here with current_step
  // like counting

  foreah step in current_step can jump to
    queue.add(step)

代碼1:通過統計每一行的結點數:

    public List<List<Integer>> levelOrder(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        deque.add(root);

        int toBePrinted = 1;
        int nextLevel = 0;

        List<Integer> level = new LinkedList<Integer>();

        while (!deque.isEmpty()) {

            TreeNode p = deque.poll();
            level.add(p.val);
            toBePrinted--;

            if (p.left != null) {
                deque.addLast(p.left);
                nextLevel++;
            }

            if (p.right != null) {
                deque.addLast(p.right);
                nextLevel++;
            }

            if (toBePrinted == 0) {
                toBePrinted = nextLevel;
                nextLevel = 0;
                rt.add(new ArrayList<Integer>(level));
                level.clear();
            }

        }

        return rt;
    }

代碼2:插入特殊結點:

    public List<List<Integer>> levelOrder2(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

        final TreeNode END = new TreeNode(0);

        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        List<Integer> level = new LinkedList<Integer>();

        deque.add(root);
        deque.add(END);

        while (!deque.isEmpty()) {

            TreeNode p = deque.pop();

            if (p == END) {
                rt.add(new ArrayList<Integer>(level));
                level.clear();

                if (!deque.isEmpty()) {
                    deque.add(END);
                }
            } else {
                level.add(p.val);

                if (p.left != null) {
                    deque.add(p.left);
                }

                if (p.right != null) {
                    deque.add(p.right);
                }
            }
        }

        return rt;
    }

Binary Tree Level Order Traversal II

Given a binary tree, return the bottom-up level order traversal of its nodes’ values. (ie, from left to right, level by level from leaf to root).

For example:
Given binary tree {3,9,20,#,#,15,7},

    3
   / \
  9  20
    /  \
   15   7

return its bottom-up level order traversal as:

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

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


參考:LeetCode 102 Binary Tree Level Order Traversal

只是在返回result前,加入一句話

Collections.reverse(result);
    public List<List<Integer>> levelOrderBottom(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

        final TreeNode END = new TreeNode(0);

        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        List<Integer> level = new LinkedList<Integer>();

        deque.add(root);
        deque.add(END);

        while (!deque.isEmpty()) {

            TreeNode p = deque.pop();

            if (p == END) {
                rt.add(new ArrayList<Integer>(level));
                level.clear();

                if (!deque.isEmpty()) {
                    deque.add(END);
                }
            } else {
                level.add(p.val);

                if (p.left != null) {
                    deque.add(p.left);
                }

                if (p.right != null) {
                    deque.add(p.right);
                }
            }
        }

        Collections.reverse(rt);
        return rt;
    }

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"]

Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.


    List<String> rt = new ArrayList<String>();
    List<Integer> path = new ArrayList<Integer>();

    public List<String> binaryTreePaths(TreeNode root) {
        findPath(root);
        return rt;
    }

    void findPath(TreeNode root) {

        if (root == null) {
            return;
        }

        path.add(root.val);

        // 是一條路徑,將path添加到rt中
        if (root.left == null && root.right == null) {
            StringBuffer sb = new StringBuffer();
            sb.append(path.get(0));
            for (int i = 1; i < path.size(); i++) {
                sb.append("->" + path.get(i));
            }
            rt.add(sb.toString());
        }

        findPath(root.left);
        findPath(root.right);

        path.remove(path.size() - 1);
    }

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].

Credits:
Special thanks to @amrsaqr for adding this problem and creating all test cases.


1. 遞歸求解

二叉樹,從右邊向左邊看。那麼除了最右邊的一個list1,還會有一個相對於最右邊的list稍微靠左邊一點的list2,如果list2比list1長,則list2較長的部分也是結果。

舉個例子:

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

list1是[1, 3, 4], list2是[1, 2, 5, 6]。list2比list1長,長出的部分是6,也在結果之中。

2. 插入特殊結點

通過插入特殊結點,來判斷一層是否結束。這樣做的好處是不用統計每一層結點數目。

3. 計數法

定義兩個變量,toBePrinted和nextLevel。

toBePrinted:當前待打印結點的數量 
nextLevel:下一層的結點數量

通過Deque來進行統計。


代碼1:遞歸求解

    public List<Integer> rightSideView(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

        rt.add(root.val);

        List<Integer> left = rightSideView(root.left);
        List<Integer> right = rightSideView(root.right);

        rt.addAll(right);

        if (left.size() > right.size()) {
            rt.addAll(left.subList(right.size(), left.size()));
        }

        return rt;

    }

代碼2:插入特殊結點

    public List<Integer> rightSideView2(TreeNode root) {

        List<Integer> rt = new ArrayList<Integer>();
        if (root == null) {
            return rt;
        }

        final TreeNode END = new TreeNode(0);

        Deque<TreeNode> deque = new LinkedList<TreeNode>();

        deque.add(root);
        deque.add(END);

        while (!deque.isEmpty()) {

            TreeNode p = deque.pop();

            if (p == END) {
                if (!deque.isEmpty()) {
                    deque.add(END);
                }
            } else {

                // 如果deque的下一個是END,則p是層序的最後一個,加入結果rt
                if (deque.peek() == END) {
                    rt.add(p.val);
                }

                if (p.left != null) {
                    deque.add(p.left);
                }

                if (p.right != null) {
                    deque.add(p.right);
                }
            }
        }

        return rt;
    }

代碼3:計數法

    public List<Integer> rightSideView3(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        deque.add(root);

        int toBePrinted = 1;
        int nextLevel = 0;

        List<Integer> level = new LinkedList<Integer>();

        while (!deque.isEmpty()) {

            TreeNode p = deque.poll();
            level.add(p.val);
            toBePrinted--;

            if (p.left != null) {
                deque.addLast(p.left);
                nextLevel++;
            }

            if (p.right != null) {
                deque.addLast(p.right);
                nextLevel++;
            }

            if (toBePrinted == 0) {
                toBePrinted = nextLevel;
                nextLevel = 0;
                rt.add(p.val);
                level.clear();
            }

        }

        return rt;
    }

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,#,#,15,7},

    3
   / \
  9  20
    /  \
   15   7

return its zigzag level order traversal as:

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

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


參考LeetCode 102 Binary Tree Level Order Traversal

只需要加入一個變量,判斷行數,翻轉list即可。

    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {

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

        if (root == null) {
            return rt;
        }

        final TreeNode END = new TreeNode(0);

        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        List<Integer> level = new LinkedList<Integer>();
        int count = 0;

        deque.add(root);
        deque.add(END);

        while (!deque.isEmpty()) {

            TreeNode p = deque.pop();

            if (p == END) {

                if (count % 2 == 1) {
                    Collections.reverse(level);
                }

                count++;

                rt.add(new ArrayList<Integer>(level));
                level.clear();

                if (!deque.isEmpty()) {
                    deque.add(END);
                }
            } else {
                level.add(p.val);

                if (p.left != null) {
                    deque.add(p.left);
                }

                if (p.right != null) {
                    deque.add(p.right);
                }
            }
        }

        return rt;
    }

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.


    int p;
    int[] postorder;
    int[] inorder;

    public TreeNode buildTree(int[] inorder, int[] postorder) {

        this.p = postorder.length - 1;
        this.inorder = inorder;
        this.postorder = postorder;

        return buildTree(0, postorder.length);
    }

    TreeNode buildTree(int start, int end) {

        if (start >= end) {
            return null;
        }

        TreeNode root = new TreeNode(postorder[p]);

        int i;
        for (i = start; i < end && postorder[p] != inorder[i]; i++)
            ;

        p--;
        root.right = buildTree(i + 1, end);
        root.left = buildTree(start, i);

        return root;
    }

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.


    int p = 0;
    int[] preorder;
    int[] inorder;

    public TreeNode buildTree(int[] preorder, int[] inorder) {

        this.preorder = preorder;
        this.inorder = inorder;

        return buildTree(0, preorder.length);
    }

    TreeNode buildTree(int start, int end) {

        if (start >= end) {
            return null;
        }

        TreeNode root = new TreeNode(preorder[p]);

        int i;
        for (i = start; i < end && preorder[p] != inorder[i]; i++)
            ;

        p++;
        root.left = buildTree(start, i);
        root.right = buildTree(i + 1, end);

        return root;
    }

Convert Sorted Array to Binary Search Tree

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


參考:LeetCode 105 Construct Binary Tree from Preorder and Inorder Traversal

只是根結點爲mid,核心代碼如下:

        int mid = (start + end) / 2;
        TreeNode root = new TreeNode(nums[mid]);

        root.left = buildBST(start, mid);
        root.right = buildBST(mid + 1, end);
    int[] nums;

    public TreeNode sortedArrayToBST(int[] nums) {

        this.nums = nums;

        return buildBST(0, nums.length);
    }

    TreeNode buildBST(int start, int end) {

        if (start >= end) {
            return null;
        }

        int mid = (start + end) / 2;
        TreeNode root = new TreeNode(nums[mid]);

        root.left = buildBST(start, mid);
        root.right = buildBST(mid + 1, end);

        return root;
    }

    public TreeNode sortedArrayToBST2(int[] nums) {

        if (nums.length == 0) {
            return null;
        }

        if (nums.length == 1) {
            return new TreeNode(nums[0]);
        }

        int mid = nums.length / 2;

        TreeNode root = new TreeNode(nums[mid]);

        root.left = sortedArrayToBST2(Arrays.copyOfRange(nums, 0, mid));
        root.right = sortedArrayToBST2(Arrays.copyOfRange(nums, mid + 1,
                nums.length));

        return root;
    }

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.


如果層序遍歷,時間複雜度是O(n)。可以使用類似二分查找的方法,因爲二叉樹是完全二叉樹,計算leftHeight和rightHeight,最大相差1,然後遞歸求解。

    public int countNodes(TreeNode root) {

        if (root == null) {
            return 0;
        }

        int leftHeight = 0;
        int rightHeight = 0;

        // 計算leftHeight
        TreeNode p = root;
        while (p != null) {
            p = p.left;
            leftHeight++;
        }

        // 計算rightHeight
        p = root;
        while (p != null) {
            p = p.right;
            rightHeight++;
        }

        // 如果相等,滿足2^n-1
        if (leftHeight == rightHeight) {
            return (1 << leftHeight) - 1;
        }

        return 1 + countNodes(root.left) + countNodes(root.right);
    }

Flatten Binary Tree to Linked List

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

For example,
Given

         1
        / \
       2   5
      / \   \
     3   4   6

The flattened tree should look like:

   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6

click to show hints.

Hints:

If you notice carefully in the flattened tree, each node’s right child points to the next node of a pre-order traversal.


    TreeNode prev;

    void preorder(TreeNode root) {

        if (root == null)
            return;

        TreeNode left = root.left;
        TreeNode right = root.right;

        // root
        if (prev != null) {
            prev.right = root;
            prev.left = null;
        }

        prev = root;

        preorder(left);
        preorder(right);
    }

    public void flatten(TreeNode root) {
        prev = null;
        preorder(root);
    }

Invert Binary Tree

Invert a binary tree.

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

to

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

Trivia:
This problem was inspired by this original tweet by Max Howell:

Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.


    public TreeNode invertTree(TreeNode root) {

        if ((root == null) || (root.left == null && root.right == null)) {
            return root;
        }

        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;

        if (root.left != null) {
            invertTree(root.left);
        }

        if (root.right != null) {
            invertTree(root.right);
        }

        return root;
    }

Kth Smallest Element in a BST

Given a binary search tree, write a function kthSmallest to find the **k**th 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?

Hint:

  1. Try to utilize the property of a BST.
  2. What if you could modify the BST node’s structure?
  3. The optimal runtime complexity is O(height of BST).

Credits:
Special thanks to @ts for adding this problem and creating all test cases.


因爲是BST,那麼中序遍歷即得到從小到大的序列。中序遍歷,到第k次即可。

    public int kthSmallest(TreeNode root, int k) {

        if (root == null) {
            return -1;
        }

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

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

            while (p != null) {
                stack.push(p);
                p = p.left;
            }

            if (!stack.isEmpty()) {
                p = stack.pop();
                if (--k == 0) {
                    return p.val;
                }
                p = p.right;
            }
        }

        return 0;
    }

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,性質是:根結點都比左結點大,比右結點小。所以給定兩個結點,找公共祖先,就是找值在兩個結點間的結點。

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

        if (root == null || p == null || q == null) {
            return null;
        }

        int m = Math.min(p.val, q.val);
        int n = Math.max(p.val, q.val);

        while (root != null) {
            if (root.val < m) {
                root = root.right;
            } else if (root.val > n) {
                root = root.left;
            } else {
                return root;
            }
        }

        return null;
    }

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.


傳統的解法是:從根結點開始,分別記錄從根結點到指定結點的路徑path1和path2,再比較path1和path2最後一個相同的結點。


http://www.fusu.us/2013/06/p2-lowest-common-ancestor-in-binary-tree.html

這個網址給出了一個更簡潔、高效的解法。主要思路是:

  1. 從葉結點開始,向上搜索
  2. 對於每一個結點node 

    • l:node的左子樹是否出現過p或q
    • r:node的右子樹是否出現過p或q
  3. 如果l和r都不是null,則該結點即爲lca

說明,對於一個結點node,l和r只可能有4種情況:

  1. l=null, r=null:node不含有p和q中的任意一個
  2. l!=null, r=null:node左子樹含有其中一個
  3. l=null, r!=null:node右子樹含有其中一個
  4. l!=null, r!=null:node左、右子樹各有其中一個(由於是從葉節點向根結點搜索,所以最先出現該情況的結點,必爲lca)

有沒有可能,p是q的祖先?沒有影響,因爲如果是自身的話,也算包含在左右子樹中。

        -1
       /  \
      0    3
     / \
   -2   4
   /
  8

具體分析:尋找結點值爲8和4的lca

  1. 首先進入結點-1,0,-2
  2. 在結點-2時,-2的左結點是8,是其中一個結點,則l置爲8,不爲空。-2的右結點是null,r仍然是null。表面-2不是lca
  3. 進入結點0,此時l已經不是null,0的右結點是4,是其中一個結點,則r置爲4,不爲空。
  4. 此時,l和r都不爲null,0就是lca
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

        // 發現目標結點,則標記(left或right)
        if (root == null || root == p || root == q)
            return root;

        // 查看左右子樹是否有目標結點
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        // 左右子樹同時含有目標結點,則該結點是lca
        if (left != null && right != null)
            return root;

        // 左右子樹只有一個含有目標結點,向上返回
        return left == null ? right : left;
    }

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 int maxDepth(TreeNode root) {

        if (root == null) {
            return 0;
        }

        int nLeft = maxDepth(root.left);
        int nRight = maxDepth(root.right);

        return nLeft > nRight ? (nLeft + 1) : (nRight + 1);
    }

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.


參考:LeetCode 104 Maximum Depth of Binary Tree

Minimum Depth的定義如下:

這裏寫圖片描述

    public int minDepth(TreeNode root) {

        if (root == null) {
            return 0;
        }

        if (root.left == null && root.right == null) {
            return 1;
        } else if (root.left != null && root.right == null) {
            return minDepth(root.left) + 1;
        } else if (root.left == null && root.right != null) {
            return minDepth(root.right) + 1;
        }

        return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
    }

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.


    boolean hasPath;

    public boolean hasPathSum(TreeNode root, int sum) {

        if (root == null) {
            return false;
        }

        hasPath = false;
        help(root, 0, sum);
        return hasPath;
    }

    void help(TreeNode node, int cur, int sum) {

        cur += node.val;

        boolean isLeaf = (node.left == null) && (node.right == null);

        if (cur == sum && isLeaf) {
            hasPath = true;
        }

        if (node.left != null) {
            help(node.left, cur, sum);
        }

        if (node.right != null) {
            help(node.right, cur, sum);
        }

        cur -= node.val;
    }

更簡潔的做法:

    public boolean hasPathSum2(TreeNode root, int sum) {

        if (root == null) {
            return false;
        }

        if (root.left == null && root.right == null) {
            return root.val == sum;
        }

        return (root.left != null && hasPathSum2(root.left, sum - root.val))
                || (root.right != null && hasPathSum2(root.right, sum
                        - root.val));
    }

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]
]

參考:LeetCode 112 Path Sum

只不過記錄了路徑。

    List<List<Integer>> result;
    List<Integer> path;
    int sum;

    public List<List<Integer>> pathSum(TreeNode root, int sum) {

        result = new ArrayList<List<Integer>>();
        path = new ArrayList<Integer>();
        this.sum = sum;

        if (root == null) {
            return result;
        }

        help(root, 0);

        return result;
    }

    void help(TreeNode node, int cur) {

        cur += node.val;
        path.add(node.val);

        boolean isLeaf = (node.left == null) && (node.right == null);

        if (cur == sum && isLeaf) {
            result.add(new ArrayList<Integer>(path));
        }

        if (node.left != null) {
            help(node.left, cur);
        }

        if (node.right != null) {
            help(node.right, cur);
        }

        cur -= node.val;
        path.remove(path.size() - 1);
    }

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

本來使用迭代的方法,利用deque去做。但是不如遞歸簡潔。

    public class TreeLinkNode {
        int val;
        TreeLinkNode left, right, next;

        TreeLinkNode(int x) {
            val = x;
        }
    }

    public void connect(TreeLinkNode root) {

        if (root == null) {
            return;
        }

        if (root.left != null && root.right != null) {
            root.left.next = root.right;
        }

        if (root.next != null && root.next.left != null) {
            root.right.next = root.next.left;
        }

        connect(root.left);
        connect(root.right);
    }

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 boolean isSameTree(TreeNode p, TreeNode q) {

        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        }

        return p.val == q.val && isSameTree(p.left, q.left)
                && isSameTree(p.right, q.right);
    }

Symmetric Tree

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

For example, this binary tree is symmetric:

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

But the following is not:

    1
   / \
  2   2
   \   \
   3    3

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

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


遞歸

參考LeetCode 100 Same Tree,僅僅將判斷條件改成p.left和q.right、p.right和q.left相比即可。

    // recursively
    public boolean isSymmetric(TreeNode root) {

        if (root == null) {
            return true;
        }

        return isSymmetric(root.left, root.right);
    }

    boolean isSymmetric(TreeNode p, TreeNode q) {

        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        }

        return p.val == q.val && isSymmetric(p.left, q.right)
                && isSymmetric(p.right, q.left);
    }

迭代

考慮用隊列,每次add兩個對應的結點。

如果隊列長度爲0,則退出循環;否則取出隊列中的兩個結點,對值進行判斷。

    // iteratively
    public boolean isSymmetric2(TreeNode root) {

        if (root == null) {
            return true;
        }

        Deque<TreeNode> deque = new LinkedList<TreeNode>();

        if (root.left == null && root.right == null) {
            return true;
        } else if (root.left == null || root.right == null) {
            return false;
        } else {
            deque.addLast(root.left);
            deque.addLast(root.right);
        }

        while (deque.size() != 0) {
            TreeNode p = deque.pop();
            TreeNode q = deque.pop();

            if (p.val != q.val) {
                return false;
            }

            if (p.left == null && q.right == null) {
                // do nothing
            } else if (p.left == null || q.right == null) {
                return false;
            } else {
                deque.addLast(p.left);
                deque.addLast(q.right);
            }

            if (p.right == null && q.left == null) {
                // do nothing
            } else if (p.right == null || q.left == null) {
                return false;
            } else {
                deque.addLast(p.right);
                deque.addLast(q.left);
            }
        }

        return true;
    }

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.

Credits:
Special thanks to @Louis1992 for adding this problem and creating all test cases.


我的最開始的思路是:先求樹的深度h,把樹中的每個結點(2^h-1)個結點,全部記錄下來,即使是null。但是這樣有些極端的測試用例會超時,比如樹中每個結點只有右結點,樹高1000。用這種方法要遍歷2^h-1次,顯然能夠優化。

參考 how LeetCode OJ serializes a binary tree的序列化方式,下面的二叉樹,序列化後的String可以是”1,2,3,null,null,4,null,5,null”,這種方法在序列化二叉樹時,只用樹結點數量規模的字符即可,省時省空間。

    1
   / \
  2   3
     / 
    4   
   /
  5
    public String serialize(TreeNode root) {

        if (root == null) {
            return "";
        }

        StringBuffer sb = new StringBuffer();

        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        deque.add(root);

        while (!deque.isEmpty()) {
            TreeNode p = deque.pop();

            if (p == null) {
                sb.append(",#");
            } else {
                sb.append("," + p.val);
                deque.add(p.left);
                deque.add(p.right);
            }
        }

        // 第一個元素前也有一個逗號,截取
        return sb.toString().substring(1);
    }

    public TreeNode deserialize(String data) {

        if (data == null || data.length() == 0) {
            return null;
        }

        String[] s = data.split(",");

        TreeNode[] node = new TreeNode[s.length];

        // 新建TreeNode,並初始化
        for (int i = 0; i < node.length; i++) {
            if (!"#".equals(s[i])) {
                node[i] = new TreeNode(Integer.valueOf(s[i]));
            }
        }

        int parent = 0;

        // 將結點連接起來
        for (int i = 0; parent * 2 + 2 < s.length; i++) {
            if (node[i] != null) {
                node[i].left = node[parent * 2 + 1];
                node[i].right = node[parent * 2 + 2];
                parent++;
            }
        }

        return node[0];
    }

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.


參考:Sum Root to Leaf Numbers

這裏寫圖片描述

    int sumNumbers(TreeNode root, int parentval) {

        if (root == null) {
            return 0;
        }

        int p = parentval * 10 + root.val;

        if (root.left == null && root.right == null) {
            return p;
        }

        return sumNumbers(root.left, p) + sumNumbers(root.right, p);
    }

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

  1. 以n爲根結點的二叉樹個數=左子樹個數*右子樹個數
  2. 用數組record[n+1]記錄以0~n的情況,自底向上,否則會超時
    public int numTrees(int n) {

        if (n == 1 || n == 2) {
            return n;
        }

        // record[0]沒有用,所以長度是n+1
        // 使用數組,從下向上保存結果,能夠節省時間,否則會超時
        int[] record = new int[n + 1];

        record[0] = 1;
        record[1] = 1; // 1個元素時,情況爲1
        record[2] = 2; // 2個元素時,情況爲2

        for (int i = 3; i <= n; i++) {
            int tmp = 0;
            for (int k = 0; k < i; k++) {
                // 以n爲根結點的二叉樹個數=左結點的二叉樹個數*右結點的二叉樹個數
                // 題目所求要包括所有情況,分別以1~n爲根結點
                tmp += (record[k] * record[i - k - 1]);
            }
            // 記錄1~i時,BST的個數
            record[i] = tmp;
        }

        return record[n];
    }

Unique Binary Search Trees II

Given 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

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


    public List<TreeNode> generateTrees(int n) {

        int[] array = new int[n];

        // 建立1~n的數組
        for (int i = 0; i < n; i++) {
            array[i] = i + 1;
        }

        return generateTrees(array);
    }

    List<TreeNode> generateTrees(int[] array) {

        if (array.length == 0) {
            return new ArrayList<TreeNode>(
                    Collections.<TreeNode> singletonList(null));
        }

        ArrayList<TreeNode> rt = new ArrayList<TreeNode>();

        // 數組的每一個元素(array[i]),分別作爲根結點
        for (int i = 0; i < array.length; i++) {
            // array[i]作爲根結點,array[i]之前的元素爲左結點,array[i]之後的元素爲右結點
            for (TreeNode left : generateTrees(Arrays.copyOfRange(array, 0, i))) {
                for (TreeNode right : generateTrees(Arrays.copyOfRange(array,
                        i + 1, array.length))) {
                    TreeNode root = new TreeNode(array[i]);

                    root.left = left;
                    root.right = right;

                    rt.add(root);
                }
            }
        }

        return rt;
    }

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.

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


驗證一棵樹是否爲BST,只需要驗證中序遍歷序列是否是遞增的。

    boolean failed = false;

    // 要用long,而不是int
    // 否則涉及到Integer.MIN_VALUE的用例會出現錯誤
    // 比如{Integer.MIN_VALUE}這個用例會錯誤
    long last = Long.MIN_VALUE;

    public boolean isValidBST(TreeNode root) {

        if (root == null) {
            return true;
        }

        inorder(root);
        return !failed;
    }

    private void inorder(TreeNode root) {

        if (root == null || failed) {
            return;
        }

        // 左
        inorder(root.left);

        // 中,相當於中序遍歷中的打印操作
        // 只採用了一個變量,所以空間複雜度是O(1)
        // 傳統的做法是建立一個ArrayList,然後判斷中序遍歷是否是遞增的,但是空間複雜度是O(n)
        if (last >= root.val) {
            failed = true;
        }
        last = root.val;

        // 右
        inorder(root.right);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章