Showing posts with label Tree. Show all posts
Showing posts with label Tree. Show all posts

leetcode Question: Different Ways to Add Parentheses

Different Ways to Add Parentheses

Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +- and *.

Example 1
Input: "2-1-1".
((2-1)-1) = 0
(2-(1-1)) = 2
Output: [0, 2]

Example 2
Input: "2*3-4*5"
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
Output: [-34, -14, -10, -10, 10]

Analysis:

The essential usage of parentheses in this problem is the order of computation. In this problem, we are asked to find every possible groups of operations in the formula.

First, let's see how to make groups in the formula. The operators is the natural way of dividing the string into groups: left part and right part. Also, the adding parentheses procedure can be converted into a more straightforward procedure: group string according different operators. For example:

String: "2-1-1"
adding () in 2-(1-1) is same to group string "2-1-1" using the 1st '-' operator: '2', '-' , '1-1'. We may also say, the left part of '-' is '2', the right part of '-' is '1-1'. So, for this grouping, the final value is "left part" - "right part".


But what if we have a long string with multiple operators? Usually recursion is a good way handling the case.  Let's see the string "2*3-4*5"

We have group:
2,    *,    3-4*5

For  the right part 3-4*5, we further take the grouping :
3,    - ,    4*5   = -17  and 3-4,    *,    5. = -5

The group  2,  *,   3-4*5,  now becomes:
2,  *,   [-17,  -5], which means, there are multiple possible values in the right part of this group. Next, just compute all the combinations of this group will give us the result:  -34 and -10.



Code(C++):

class Solution {
public:
    vector<int> search(string input){
        vector<int> res;
        vector<int> left;
        vector<int> right;
        
        if (input.find('+')==-1 &&input.find('-')==-1 && input.find('*')==-1){
            int tmp;
            stringstream(input) >> tmp;
            res.push_back(tmp);
        }else{
            for (int i=1; i<input.size(); i++){
                if (input[i] == '+' || input[i] == '-' ||input[i] == '*'){
                    left = search(input.substr(0,i));
                    right = search(input.substr(i+1));
                    for (int j=0;j<left.size();j++){
                        for (int k=0;k<right.size();k++){
                            int val = 0;
                            if (input[i] == '+') {val = left[j]+right[k];}
                            if (input[i] == '-') {val = left[j]-right[k];}
                            if (input[i] == '*') {val = left[j]*right[k];}
                            res.push_back(val);
                        }
                    }
                }
            }
        }
        return res;
    }

    vector<int> diffWaysToCompute(string input) {
        vector<int> result;
        if (input.size() == 0){ return result; }
        return search(input);
        
    }
};

Code(Python):

class Solution(object):
    def diffWaysToCompute(self, input):
        """
        :type input: str
        :rtype: List[int]
        """
        res = []
        right = []
        left = []
        if len(input) == 0:
            return res
        if input.find('+') == -1 and input.find('-') == -1 and input.find('*') == -1:
            res.append(int(input))
        else:
            count = 0
            for ch in input:
                if ch in ['+', '-', '*']:
                    left = self.diffWaysToCompute(input[0:count])
                    right = self.diffWaysToCompute(input[count+1::])
                    for l in left:
                        for r in right:
                            val = 0
                            if ch == '+':
                                val = l + r
                            if ch == '-':
                                val = l - r
                            if ch == '*':
                                val = l * r
                            res.append(val)
                count+=1
        return res
        
                            
                
        

leetcode Question: Binary Tree Paths

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

Analysis:


This is a classic depth first search problem.
The idea is

  1. Starting from the root node (remember to check NULL)
  2. Add current node into path (a string in function parameter) 
  3. Check if the current node is a leaf node: if yes, then save path
  4. Keep searching the left and right child of current node.



Code(C++):


/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void dfs(TreeNode* root, string str, vector<string> &res){
        if (!root){
           return;
        }else{
            if (str == ""){
                str += to_string(root->val);
            }else{
                str = str + "->" + to_string(root->val);    
            }
            if (!root->right && !root->left){
                if (str!=""){
                    res.push_back(str);
                }
            }
            dfs(root->left, str,res);
            dfs(root->right, str,res);
        }
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        string str = "";
        vector<string> res;
        dfs(root,str,res);
        return res;
    }
};

Code(Python):


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def dfs(self, root, s, res):
        if not root:
            return
        else:
            if s == "":
                s += str(root.val)
            else:
                s = s + "->" + str(root.val)
            if not root.right and not root.left:
                if s != "":
                    res.append(s)
            self.dfs(root.right,s,res)
            self.dfs(root.left,s,res)
    
    # @param {TreeNode} root
    # @return {string[]}
    def binaryTreePaths(self, root):
        res = []
        s = ""
        self.dfs(root, s, res)
        return res

leetcode Question: Lowest Common Ancestor of a Binary Tree

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.






The solution of this question is same as here.

leetcode Question: Lowest Common Ancestor of a Binary Search Tree

 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.

Analysis:


One obvious way to solve this problem is to utilizing the properties of Binary Search Tree:

  • It is ordered when you do Tree traversal
However, in this post, we are solving this problem in a more general way. (It is same as the problem here).

The idea is simple: recursion.

Usually when I do recursion problem, I consider:

  • What are we looking for?
  • What is the termination condition?
  • Which direction do we go for the searching?
According to this problem:
  • We are looking for the common ancestor. In other words, if the two node are in the current node's left and right child, respectively, current node is thus the lowest common ancestor.
  • When do we stop search? 1. Null node. 2. meet either one of the two nodes, the ancestor is this node or above.
  • Which direction do we go ? For a binary tree, left and right.  
So, we start the search from the root node, recursively find the common ancestor for root->left and root->right, if both of them are existed, which means root is the lowest common ancestor, otherwise, the existed one is the result.



Code(C++):

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (!root){
            return NULL;
        }
        if (root == p || root == q){
            return root;
        }else{
            TreeNode* lc = lowestCommonAncestor(root->left, p, q);
            TreeNode* rc = lowestCommonAncestor(root->right, p, q);
            if (lc && rc){
                return root;
            }else{
                if (lc){return lc;}
                if (rc){return rc;}
            }
        }
    }
};

Code(Python):


# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: TreeNode
        :type q: TreeNode
        :rtype: TreeNode
        """
        if not root:
            return None
        if root == p or root == q:
            return root
        else:
            lc = self.lowestCommonAncestor(root.left, p, q)
            rc = self.lowestCommonAncestor(root.right, p, q)
            if lc and rc:
                return root
            else:
                if lc:
                    return lc
                if rc:
                    return rc
        
            

leetcode Question: Kth Largest Element in an Array

Kth Largest Element in an Array


Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4] and k = 2, return 5.
Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.

Analysis:

This is a good practice of using data structure Heap ! We know that C++ STL already has heap operations, but here in this post, I'd like to write the heap data structure of our own. In one of my previous post (here), I have already introduced the heap sort, in which the code can be applied in this problem perfectly.  Now I will briefly describe how to construct a heap.

In this problem, we utilize array  (list in python) to represent heap, literally heap is a Tree structure, which has the following property:
The value of parent node is greater/smaller than that of its children.
(Be careful with the definition, it has no constrains about the child nodes in the same level)

Before we start to construct heap, firstly let's review the tree representation using array. Simply, let's use a vector<int> to define a binary tree A, where the value of node is type int. Then let's define the tree structure:
(1) Every element is used to represent a tree node.
(2) The root node is defined as the 1st element of A, A[0].
(3) For each node A[i], its left child is A[i*2+1], its right child is A[i*2+2].
(4) For each node A[i], its parent node is A[(i-2)/2], when (i-2)/2 >=0

This is not a very complete definition, but enough for our heap implementation. Now we construct the heap, as well as heap sort algorithm.

The most important step in the algorithm is called "downshift". This downshift operation, takes the root node of the binary tree, compare to its left and right children, swap the value with the greater/smaller child, recursively.  This can be implemented as a standalone function.

Since the tree leaves has no child node, so the leaf nodes are left without any downshift operation. To construct the heap, we can downshift all the non-leaf nodes, from bottom to top. After this loop, the tree is now called a heap.

In order to get the heap sort result (which is usually an array), one more operation is needed. Currently the heap is a binary tree, to get the sorted array, every time we take the root node (which is biggest/smallest element), and then swap the root node with the last node in the tree. (Remember we have used an array to represent a tree?) , then apply downshift of the root node, to keep the tree as a heap.


Code(C++):

class Solution {
public:
    void downshift(vector<int> &h, int n, int parent){
        if (parent < 0){return;}
        int left = parent*2+1;
        int right = parent*2+2;
        int mxch;
        if (left>=n) {return;}
        if (right>=n){mxch=left;}
        else{
            mxch = h[left]>=h[right]?left:right;
        }
        if (h[parent]<h[mxch]){
            int tmp = h[parent];
            h[parent] = h[mxch];
            h[mxch] = tmp;
            downshift(h,n,mxch);
        }
    }


    void constructHeap(vector<int>& h, int n){
        int parent = (n-2/2);
        for (; parent>=0;parent--){
            downshift(h, n, parent);
        }
    }
    
    void heapsort(vector<int> &h, int n){
        constructHeap(h,n);
        int i=n-1;
        vector<int> b(n,0);
        while (i>=0){
            b[n-i-1]=h[0];
            int tmp = h[0];
            h[0] = h[i];
            h[i] = tmp;
            downshift(h,i,0);
            i--;
        }
        for (int i=0;i<n;i++){
            h[i] = b[i];
        }
    }
    
    int findKthLargest(vector<int>& nums, int k) {
        heapsort(nums,nums.size());
        return nums[k-1];
    }
};


Code(Python):

class Solution:
    def downshift(self, nums, n, parent):
        if parent < 0:
            return
        left = parent * 2 + 1
        right = parent * 2 + 2
        if left >= n:
            return
        if right >=n:
            mxch = left
        else:
            if nums[left] >= nums[right]:
                mxch = left
            else:
                mxch = right
                
        if nums[parent]<nums[mxch]:
            nums[parent], nums[mxch] = nums[mxch], nums[parent]
            self.downshift(nums, n, mxch)

    def constructHeap(self, nums, n):
        parent = (n-2)/2
        for i in range(parent,-1,-1):
            self.downshift(nums, n, i)
    
    def heapSort(self, nums, n):
        self.constructHeap(nums, n)
        i = n - 1
        num_tmp = []
        while i>=0:
            num_tmp.append(nums[0])
            nums[0], nums[i] = nums[i], nums[0]
            self.downshift(nums,i,0)
            i -= 1
        return num_tmp
    
    # @param {integer[]} nums
    # @param {integer} k
    # @return {integer}
    def findKthLargest(self, nums, k):
        new = self.heapSort(nums,len(nums))
        return new[k-1]
        

leetcode Question: Implement Trie (Prefix Tree)

Implement Trie (Prefix Tree)

Implement a trie with insertsearch, and startsWith methods.
Note:
You may assume that all inputs are consist of lowercase letters a-z.

Analysis:

This is a classic problem related to data structure Trie. Trie is an important data structure which is very efficient for searching.  In this post, I just present the basic structure of the Trie as an introduction for beginners.

Typically, the Trie is an n-nodes tree structure, where each node has two fields:
(1) int value; //Briefly understanding, this value is to check weather this node is a word end or not.
(2) TrieNode* children[size_of_alphabet]; //This saves the tree structure.

Figure (coming from wikipedia) below shows a Trie, given keys "A", "to", "tea", "ted", "ten", "i", "in", and "inn".:

The general idea of building a Trie given a set of keys(strings) is as following:
1.  Get string S.
2.  Set pointer P as the root.
3.  Start from the 1st char C in S,
         if C does not exist in the children of current node P:
                 add a new node C to P
4.  Set P = P.C, goto step 3.
5. Set a value to the last char node (indicate this node is not only a prefix but a word).          


Some basic operations of Trie (only for this problem):
1. Insert String:
      Step 1: set pointer p as the root node
      Step 2: Start from the 1st char in the string, get the char, check if exist in p's children.
      Step 3: if not exist, create a new children for p,
      Step 4: set p = p->children[ current char], continue search until meets the string end.
      Step 5: set p->value to 1; (in this problem set to a constant is enough)  

2. Search String is pretty much similar to the insert operation. Only differences are (1) If no children exists, return false. (2) When meets the end of string, check the value of last node, to see if this is the word end, or just a prefix key.

3. Startwith is very similar to search, but no need to check the value of the node.

This problem is pretty, details see the code below. I will write more details related to Trie later.

Code(C++):

class TrieNode {
public:
    // Initialize your data structure here.
    TrieNode() {
        value = 0;
        for (int i=0;i<26;i++){
            children[i] = NULL;
        }
    }
    int value;
    TrieNode* children[26];
};

class Trie {
public:
    Trie() {
        root = new TrieNode();
        count = 0;
    }

    // Inserts a word into the trie.
    void insert(string s) {
        TrieNode *p = root;
        int len = s.size();
        for (int i=0;i<len;i++){
            int idx = s[i] - 'a';
            if (! p->children[idx]){
                p->children[idx] = new TrieNode();
            }
            p = p->children[idx];
        }
        count++;
        p->value = count;
    }

    // Returns if the word is in the trie.
    bool search(string key) {
        TrieNode *p = root;
        int len = key.size();
        for (int i=0;i<len;i++){
            int idx = key[i] - 'a';
            if (p->children[idx]){
                p = p->children[idx];
            }else{
                return false;
            }
        }
        if (p->value!=0){
            return true;
        }else{
            return false;
        }
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    bool startsWith(string prefix) {
        TrieNode *p = root;
        int len = prefix.size();
        for (int i=0;i<len;i++){
            int idx = prefix[i] - 'a';
            if (p->children[idx]){
                p = p->children[idx];
            }else{
                return false;
            }
        }
      return true;
    }

private:
    TrieNode* root;
    int count;
};

// Your Trie object will be instantiated and called as such:
// Trie trie;
// trie.insert("somestring");
// trie.search("key");

Code(Python):

class TrieNode:
    # Initialize your data structure here.
    def __init__(self):
        self.value = 0
        self.children = [None] * 26
        

class Trie:

    def __init__(self):
        self.root = TrieNode()

    # @param {string} word
    # @return {void}
    # Inserts a word into the trie.
    def insert(self, word):
        p = self.root
        for ch in word:
            idx = ord(ch) - ord('a')
            if not p.children[idx]:
                p.children[idx] = TrieNode()
            p = p.children[idx]
        p.value = 1;
                

    # @param {string} word
    # @return {boolean}
    # Returns if the word is in the trie.
    def search(self, word):
        p = self.root
        for ch in word:
            idx = ord(ch) - ord('a')
            if not p.children[idx]:
                return False
            p = p.children[idx]
        if p.value != 0:
            return True
        else:
            return False
                

    # @param {string} prefix
    # @return {boolean}
    # Returns if there is any word in the trie
    # that starts with the given prefix.
    def startsWith(self, prefix):
        p = self.root
        for ch in prefix:
            idx = ord(ch) - ord('a')
            if not p.children[idx]:
                return False
            p = p.children[idx]
        return True
        

# Your Trie object will be instantiated and called as such:
# trie = Trie()
# trie.insert("somestring")
# trie.search("key")

leetcode Question: Binary Tree Right Side View

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

Analysis:


Note that in this problem, it is NOT to print out the right most sub tree.
It is to print out the most right element in each level.
Therefore the problem becomes pretty straightforward, which easily reminds us one of the basic tree operations:  level order traversal.

Similar to my previous post (here), we can use two queues to do the level order traversal. The only difference is in this question, we only need to store the 'last' element in each level and save it to the result vector. Implementation details can be seen in the following code.


Code(C++):

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        queue<TreeNode*> p, q;
        vector<int> res;
        if (!root) return res;
        
        p.push(root);
        while (1){
            int last;
            while (!p.empty()){
                TreeNode* cur = p.front();
                if (cur->left) q.push(cur->left);
                if (cur->right) q.push(cur->right);
                last = cur->val;
                p.pop();
            }
            res.push_back(last);
            p=q;
            while (!q.empty()){q.pop();}
            if (p.empty()) return res;
        }
    }
};

Code(Python):

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    # @param {TreeNode} root
    # @return {integer[]}
    def rightSideView(self, root):
        res = []
        if not root:
            return res
        p = []
        q = []
        p.append(root)
        while True:
            last = root.val
            while p:
                if p[0].left:
                    q.append(p[0].left)
                if p[0].right:
                    q.append(p[0].right)
                last = p[0].val
                p.pop(0);
            res.append(last)
            p = q
            q = []
            if not p:
                return res


leetcode Question: Binary Tree Postorder Traversal (iteration)

Binary Tree Postorder Traversal (iteration)

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?

Analysis:

Classical problem,  the recursion version of the solution can be easily found by modifying here. In this post, I solved it iteratively.  Which data structure do remind us ?  Yes! Still stack!

The algorithm has following steps, which is slight different from the previous question:
(1) Push the root node into the stack.
(2) while the stack is not empty, do:
       if 
          the top node is a leaf node (no left&right children), pop it.
          or if the top node has been visited, pop it. (here we use a sign head to show the latest popped node, if the top node's child = the latest popped node, either left or right, it must has been visited.)
       else
          b. push the right child of the top node (if exists)
          c. push the left child of the top node (if exists)

Code (C++):

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode *root) {
        stack<TreeNode*> st;
        vector<int> res;
        if (!root){return res;}
        st.push(root);
        TreeNode* head=root;
        while (!st.empty()){
            TreeNode* top = st.top();
            if ((top->left==NULL && top->right==NULL)||top->right==head || top->left==head){
                res.push_back(top->val);
                st.pop();
                head = top;
            }else{
                if (top->right!=NULL){st.push(top->right);}
                if (top->left!=NULL){st.push(top->left);}
            }
        }
        return res;
    }
};

Code(Python):


# Definition for a  binary tree node
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    # @param root, a tree node
    # @return a list of integers
    def postorderTraversal(self, root):
        res = []
        st = []
        if root != None:
            st.append([root,False])
            while len(st) != 0:
                tmp = st[-1]
                if tmp[1] == True:
                    res.append(st.pop()[0].val)
                elif tmp[0].left == None and tmp[0].right == None:
                    res.append(st.pop()[0].val)
                else:
                    st[-1][1] = True
                    if tmp[0].right != None:
                        st.append([tmp[0].right, False])
                    if tmp[0].left != None:
                        st.append([tmp[0].left, False])
        return res
        
        

        

leetcode Question: Binary Tree Preorder Traversal (iteration)

Binary Tree Preorder Traversal (iteration)

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?

Analysis:


Classical problem,  the recursion version of the solution can be found here (you need do slight modification, can you do that?) . In this post, I solved it iteratively.  Which data structure do remind us ?  Yes! Stack!

The algorithm has following steps:
(1) Push the root node into the stack.
(2) while the stack is not empty, do:
       a. pop the top node and print it.
       b. push the right child of the top node (if exists)
       c. push the left child of the top node (if exists)



Code(C++):


/**
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        stack<TreeNode*> st;
        vector<int> res;
        if (!root){return res;}
        st.push(root);
        TreeNode* head=root;
        while (!st.empty()){
            TreeNode* top = st.top();
            res.push_back(top->val);
            st.pop();
            if (top->right!=NULL){st.push(top->right);}
            if (top->left!=NULL){st.push(top->left);}
        }
        return res;
    }
};

Code(Python):


# Definition for a  binary tree node
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    # @param root, a tree node
    # @return a list of integers
    def preorderTraversal(self, root):
        res = [] 
        st = []
        if root != None:
            st.append(root)
            while len(st) != 0:
                tmp = st.pop()
                res.append(tmp.val)
                if (tmp.right != None):
                    st.append(tmp.right)
                if (tmp.left != None):
                    st.append(tmp.left)
        return res

 

leetcode Question 130: Sum Root to Leaf Numbers

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.

Analysis:

Once we see this kind of problem, no matter what sum is required to output, "all root-to-leaf" phrase reminds us the classic Tree Traversal or Depth-First-Search algorithm. Then according to the specific problem, compute and store the values we need. Here in this problem, while searching deeper, add the values up (times 10 + current value), and add the sum to final result if meet the leaf node (left and right child are both NULL).

Code(C++):

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:

    void dfs(TreeNode* root,int cur, int &res){
        if (root->left==NULL && root->right==NULL){
            cur=cur*10+root->val;
            res+=cur;
        }else{
            cur=cur*10+root->val;
            if (root->left){
                dfs(root->left,cur,res);
            }
            if (root->right){
                dfs(root->right,cur,res);
            }
        }
    }
    int sumNumbers(TreeNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int res=0;
        if (!root){return res;}
        dfs(root,0,res);
        return res;
    }
};

Code(Python):


# Definition for a  binary tree node
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    # @param root, a tree node
    # @return an integer
    res = 0
    def search(self, root, path):
        if root.left == None and root.right == None:
            self.res += path + root.val
        else:
            if root.left != None:
                self.search(root.left, (path + root.val)*10)
            if root.right != None:
                self.search(root.right, (path + root.val)*10)
            
    def sumNumbers(self, root):
        self.res = 0
        if root == None:
            return 0
        else:
            self.search(root, 0)
            return self.res
            
        
        

leetcode Question 90: Same Tree

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.

Analysis:

Recursively check the left child and right child.  If the value is different, or if one of the two nodes is null, return false.

Code(C++):

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSameTree(TreeNode *p, TreeNode *q) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (!p && !q) {return true;}
        if ((!p && q) || (!q && p)){return false;}
        if (p->val!=q->val){return false;}
        return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
    }
};

Code(Python):


# Definition for a  binary tree node
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    # @param p, a tree node
    # @param q, a tree node
    # @return a boolean
    def isSameTree(self, p, q):
        if p == None and q == None:
            return True
        elif p == None and q != None:
            return False
        elif p != None and q == None:
            return False
        elif p.val != q.val:
            return False
        else:
            return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
            
            
        

leetcode Question 109: Symmetric Tree

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.

Updated Solution (2014.02)


Analysis:
Use two queue to store each level of nodes back and force instead of storing the level.
Use a special node to store the empty node. (-999 in the code below).
Details see the comments in the code below.

Code:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool valid(vector<int> &l){
        int i=0;
        int j=l.size()-1;
        while (i<j){
            if (l[i++]!=l[j--]){return false;}
        }
        return true;
    }
    
    
    bool isSymmetric(TreeNode *root) {
        vector<int> l;  //store the values in current level
        
        //q1 and q2 stores the current and next level TreeNodes
        queue<TreeNode*> q1; 
        queue<TreeNode*> q2;
        
        if (!root){return true;}
        
        q1.push(root);
        while ((!q1.empty()) || (!q2.empty())){  // exit only when both queue are empty
            if (q2.empty()){   // current level is q1
                while (!q1.empty()){ // push all the q1 nodes' childeren into q2
                    TreeNode* tmp = q1.front();
                    q1.pop(); 
                    l.push_back(tmp->val);
                    if (tmp->val!=-999){ // if current node is not a empty node
                        if (tmp->left!=NULL){q2.push(tmp->left);}
                        else{TreeNode* emp = new TreeNode(-999); q2.push(emp);} // store the empty node for the balance checking 
                        if (tmp->right!=NULL){q2.push(tmp->right);}
                        else{TreeNode* emp = new TreeNode(-999); q2.push(emp);}
                    }
                }
                
                if (valid(l)==false){return false;}else // all the nodes in current level are stored, check if it is balanced
                {l.clear();}
                
            }else{  //current level is q2
                while (!q2.empty()){  // push all the q2 nodes' childeren into q1
                    TreeNode* tmp = q2.front();
                    q2.pop();
                    l.push_back(tmp->val);
                    if (tmp->val!=-999){
                        if (tmp->left!=NULL){q1.push(tmp->left);}
                        else{TreeNode* emp = new TreeNode(-999); q1.push(emp);}
                        if (tmp->right!=NULL){q1.push(tmp->right);}
                        else{TreeNode* emp = new TreeNode(-999); q1.push(emp);}
                    }
                }
                
                if (valid(l)==false){return false;}else
                {l.clear();}
            }
        }
            
        return true;
    }
};


Code(Python):

# Definition for a  binary tree node
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    # @param root, a tree node
    # @return a boolean
    def valid(self, l):
        if cmp(l, l[::-1]) == 0:
            return True
        else:
            return False
    def isSymmetric(self, root):
        if root == None:
            return True
        q1 = []
        q2 = []
        l = []
        q1.append(root)
        while len(q1) != 0 or len(q2) != 0:
            if len(q1) == 0:
                while len(q2) != 0:
                    node = q2.pop(0)
                    l.append(node.val)
                    if node.val != -999:
                        if node.left != None:
                            q1.append(node.left)
                        else:
                            q1.append(TreeNode(-999))
                        if node.right != None:
                            q1.append(node.right)
                        else:
                            q1.append(TreeNode(-999))
                if self.valid(l) == False :
                    return False
                else:
                    l = []
            else:
                while len(q1) != 0:
                    node = q1.pop(0)
                    l.append(node.val)
                    if node.val != -999:
                        if node.left != None:
                            q2.append(node.left)
                        else:
                            q2.append(TreeNode(-999))
                        if node.right != None:
                            q2.append(node.right)
                        else:
                            q2.append(TreeNode(-999))
                if self.valid(l) == False :
                    return False
                else:
                    l = []
        return True
            
        







Updated Solution(2013.09)

Analysis:
BFS is a good way solving this problem, since BFS can get the nodes in every level.
But be careful with the empty nodes in this problem, if they are not well treated, it will effect the result.
Idea here is to save the empty nodes, with a special value (e.g. -999 in my code), and when we get all the nodes in one level, just need to do the testing (like palindrome).

Note that, the node with no children also need save its two "empty" children. If not, consider this example:
                   2
           3            3
        4    5      5    4    
            8  9        9  8    
 The last level, if you do not store the empty children from 4 and 5 in previous level, it becomes:
 [8,9,9,8], which seems a true answer. But,  this level here is [#, #, 8, 9, #, #, 9, 8],  #!=8, which is a false answer!

Details see the code below:


Code:
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool valid(vector<int> a){
        int st=0;
        int ed=a.size()-1;
        while (st<ed){
            if (a[st]!=a[ed]){return false;}
            else{ st++; ed--;}
        }
        return true;
    }

    bool isSymmetric(TreeNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        queue<TreeNode* > q1;
        queue<int> q2;      
        if (!root){return true;}
        q1.push(root);
        q2.push(0);
        int l=0;
        vector<int> r;
        while (!q1.empty()){
            if (l==q2.front()){
                r.push_back(q1.front()->val);
            }else{
                if (valid(r)==false){return false;}
                r.clear();
                r.push_back(q1.front()->val);
                l=q2.front();
            }
        
            if (q1.front()->val==-999){
                q1.pop();
                q2.pop();
                continue;
            }

            if (q1.front()->left){
                q1.push(q1.front()->left);
                q2.push(l+1);
            }else{
                TreeNode* tmp = new TreeNode(-999);
                q1.push(tmp);
                   q2.push(l+1);
            }
            
            if (q1.front()->right){
                q1.push(q1.front()->right);
                q2.push(l+1);
            }else{
                TreeNode* tmp = new TreeNode(-999);
                q1.push(tmp);
                q2.push(l+1);
            }
            q1.pop();
            q2.pop();
        }
        if (!valid(r)){return false;}
        return true;
    }
};

leetcode Question 114: Unique Binary Search Trees

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


Analysis:

DP works well in this problem.

For each sequence from 1 to n, # of BSTs equals:
Sum of BSTs where each number (from 1 to n) is considered as the root node.
For each node, # of BSTs equals:
# of bsts of its left child times # of bsts of its right child.


Denote bst[i] = the number of BSTs can be constructed that store values from 1..n.

n = 1,  Node = {1},      bst[1]  = 1

n = 2,  Node = {1, 2}
when 1 is the root node, there is 1 bst
   1
    \
    2
when 2 is the root node, there is 1 bst
   2
  /
1
bst[2] = 2

n = 3,  Node = {1, 2, 3}
when 1 is the root node, bst[3] =  bst[3] + bst[2] where stores 2 values (2 and 3)
1                                                   1                   1
 \                                 =                 \                    \
 BSTs of {2,3}                              2                    3
                                                       \                   /
                                                        3                2
when 2 is the root node, bst[3] =  bst[3] + bst[1] + bst[1]
          2
         /  \
        1   3
when 3 is the root node, bst[3] =  bst[3] + bst[2] where stores 2 values (1 and 2)
                   3                                 3                   3
                /                 =                 /                    /
 BSTs of {1,2}                            2                   1
                                                   /                       \
                                                 1                         2







Code(C++):

class Solution {
public:
    int numTrees(int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<int> table(n+1,0);
        if (n==0){return 0;}
        table[0]=1;
        table[1]=1;
        table[2]=2;
        for (int i=3;i<=n;i++){
            int res=0;
            for (int j=0;j<=i-1;j++){
                res = res+ table[j]*table[i-1-j];
            }
            table[i]=res;
        }
        return table[n];   
    }
};

Code(Python):

class Solution:
    # @return an integer
    def numTrees(self, n):
        if n <= 1:
            return 1
        res = [0 for x in range(n + 1)]
        res[0] = 1
        res[1] = 1
        i = 2
        while i <= n :
            for j in xrange(i):
                res[i] = res[i] + res[j]* res[i-j-1]
            i = i + 1
        return res[n]



leetcode Question 73: Populating Next Right Pointers in Each Node II

Populating Next Right Pointers in Each Node II

Follow up for problem "Populating Next Right Pointers in Each Node".
What if the given tree could be any binary tree? Would your previous solution still work?
Note:
  • You may only use constant extra space.
For example,
Given the following binary tree,
         1
       /  \
      2    3
     / \    \
    4   5    7
After calling your function, the tree should look like:
         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \    \
    4-> 5 -> 7 -> NULL




New updates (201308):
Idea is to use dfs and only constant space is used. The key is to use the "next" pointer and search right child first then the left child. Details see the code comment.

Code:
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void dfs(TreeLinkNode *root){
        if (!root){return;}  // if current node is not valid return
        
        if (root->next==NULL){ // if current node is not in the right boundary of this level
            if (root->right){root->right->next = NULL;} // if has right child, its next is null
            if (root->left){root->left->next = root->right;}//if has left child, its next is its right
        }else{ // if the current node has next node in its right
            TreeLinkNode* p = root->next; //the pointer travle along this level 
            TreeLinkNode* q=NULL; // the next valid pointer in the level+1 , or NULL if not found
            while (p){ //find the next valid child of root node
                if (p->left){q =p->left; break;}
                if (p->right){q =p->right; break;}
                p=p->next;
            }
            if (root->right){root->right->next = q;} //set right child if exists
            if (root->left && root->right ){root->left->next = root->right;}//set left if right exists
            if (root->left && !root->right) {root->left->next = q;} // set left if right not exist
        }
        
        dfs(root->right); // search right child, order is important
        dfs(root->left);  // search left child
    }
    void connect(TreeLinkNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (!root){return;}
        root->next = NULL;
        dfs(root);
    }
};








Old solution (BFS):
Idea is almost the same to previous problem.
Just we cannot use the level information directly, so we can store the level info!
Use a pair instead of a single tree node in the queue.
Details see the code.

Code:
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void connect(TreeLinkNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        queue<pair<TreeLinkNode*, int> > que;
        if (root==NULL) {return;}
        que.push(pair<TreeLinkNode*, int>(root,1));
        
        while (!que.empty()){
            pair<TreeLinkNode*, int>p =que.front();
            que.pop();
            if (p.first->left!=NULL){
                que.push(pair<TreeLinkNode*, int>(p.first->left,p.second+1));
            }
            if (p.first->right!=NULL){
                que.push(pair<TreeLinkNode*, int>(p.first->right,p.second+1));
            }
            
            if (que.empty()){
                p.first->next = NULL;
                return;
            }
            if (p.second != que.front().second){
                p.first->next = NULL;
            }else{
                p.first->next = que.front().first;
            }
        }
         
    }
};

leetcode Question 72: Populating Next Right Pointers in Each Node

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


New updates (201308):
Idea is to use dfs and only constant space is used. The key is to use the "next" pointer and search right child first then the left child. Details see the code comment.

Code:
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void dfs(TreeLinkNode *root){
        if (!root){return;}  // if current node is not valid return
        
        if (root->next==NULL){ // if current node is not in the right boundary of this level
            if (root->right){root->right->next = NULL;} // if has right child, its next is null
            if (root->left){root->left->next = root->right;}//if has left child, its next is its right
        }else{ // if the current node has next node in its right
            TreeLinkNode* p = root->next; //the pointer travle along this level 
            TreeLinkNode* q=NULL; // the next valid pointer in the level+1 , or NULL if not found
            while (p){ //find the next valid child of root node
                if (p->left){q =p->left; break;}
                if (p->right){q =p->right; break;}
                p=p->next;
            }
            if (root->right){root->right->next = q;} //set right child if exists
            if (root->left && root->right ){root->left->next = root->right;}//set left if right exists
            if (root->left && !root->right) {root->left->next = q;} // set left if right not exist
        }
        
        dfs(root->right); // search right child, order is important
        dfs(root->left);  // search left child
    }
    void connect(TreeLinkNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (!root){return;}
        root->next = NULL;
        dfs(root);
    }
};








Old solution (BFS):
We know that the tree is full binary tree, which is a very powerful condition that we can use.
As can be seen in the tree above, we need to deal with the nodes according to each level of the tree.
Easily the level-order traversal popped out!
What we need? Yes, just a queue!
What about the level?  Here comes the condition of this problem. A full binary tree which have  ith level have
2^i - 1 nodes.

Once we have the queue, the problem is quite easy. Just make the last node's next pointer NULL, set other nodes' next to the next element in the queue. Well done!

The space needed is less than 2^i-1;


Code:
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void connect(TreeLinkNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        queue<TreeLinkNode*> que;
        if (root==NULL) {return;}
        que.push(root);
        int i=1;
        int l=1;
        while (!que.empty()){
            TreeLinkNode* p =que.front();
            que.pop();
            if ((p->right!=NULL)&&(p->left!=NULL)){
                que.push(p->left);
                que.push(p->right);
            }
            if (i==(pow(2,l)-1)){
                p->next = NULL;
                i++;
                l++;
            }else{
                p->next = que.front();
                i++;
            }
        }
        
    }
};

leetcode Question 67: Path Sum II

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


Analysis:


Classic DFS search similar to the Question Path Sum I, in this problem we just add a vector<int> to store the result.
Details see code below:

Code(C++):


/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void ps(TreeNode* root, int sum, vector<int> path, vector<vector<int>> &res){
        if (!root){
            return;
        }else{
            path.push_back(root->val);
            if (!root->left && !root->right && sum==root->val){
                res.push_back(path);
                path.clear();
            }
            ps(root->left, sum - root->val, path, res);
            ps(root->right, sum - root->val, path, res);
        }
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> res;
        vector<int>path;
        ps(root, sum, path, res);
        return res;
    }
};

Code(Python):

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def ps(self, root, sum, path, res):
        if not root:
            return
        else:
            path.append(root.val)
            if not root.left and not root.right and sum == root.val:
                res.append(path)
                path = []
            else:
                self.ps(root.left, sum - root.val, path, res)
                self.ps(root.right, sum - root.val, path, res)
    
    def pathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: List[List[int]]
        """
        res = []
        path = []
        self.ps(root, sum, path, res)
        return res