Showing posts with label binary tree. Show all posts
Showing posts with label binary tree. Show all posts

Monday, August 7, 2017

[Leetcode] Kth Smallest Element in a BST, Solution

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note: 
You may assume k is always valid, 1 ? k ? BST's total elements.
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?

[Thoughts]
递归遍历二叉树,在遍历过程中算kth。


[Code]
1:    int kthSmallest(TreeNode* root, int k) {  
2:      int count = 0;  
3:        
4:      return kthSmallestImpl(root, count, k);  
5:        
6:    }  
7:      
8:    int kthSmallestImpl(TreeNode* root, int& count, int k) {  
9:      if(root == NULL) return -1;  
10:        
11:      int lr = kthSmallestImpl(root->left, count, k);  
12:      count++;  
13:      if(count == k) {  
14:        return root->val;  
15:      }  
16:        
17:      int rr = kthSmallestImpl(root->right, count, k);  
18:      return lr != -1 ? lr : rr;  
19:    }  

[Leetcode] Closest Binary Search Tree Value, Solution

Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.
Note:
  • Given target value is a floating point.
  • You are guaranteed to have only one unique value in the BST that is closest to the target.
[Thoughts]
遍历二叉搜索树,在遍历的过程中,对于遍历节点记录closest。


[Code]
1:    int closestValue(TreeNode* root, double target) {  
2:      double min = UINT_MAX;  
3:      int closeVal = 0;  
4:        
5:      closest(root, target, min, closeVal);  
6:      return closeVal;  
7:    }  
8:      
9:    void closest(TreeNode* root, double target, double& min, int& closeVal) {  
10:      if(root == NULL) return;  
11:        
12:      if(abs(target - root->val) < min) {  
13:        closeVal = root->val;  
14:        min = abs(target - root->val);  
15:      }  
16:        
17:      if(root->val < target) {  
18:        closest(root->right, target, min, closeVal);  
19:      }else {  
20:        closest(root->left, target, min, closeVal);  
21:      }  
22:    }  



[Leetcode] Binary Tree Vertical Order Traversal, Solution

Given a binary tree, return the vertical order traversal of its nodes' values. (ie, from top to bottom, column by column).
If two nodes are in the same row and column, the order should be from left to right.
Examples:
  1. Given binary tree [3,9,20,null,null,15,7],
       3
      /\
     /  \
     9  20
        /\
       /  \
      15   7
    
    return its vertical order traversal as:
    [
      [9],
      [3,15],
      [20],
      [7]
    ]
    
  2. Given binary tree [3,9,8,4,0,1,7],
         3
        /\
       /  \
       9   8
      /\  /\
     /  \/  \
     4  01   7
    
    return its vertical order traversal as:
    [
      [4],
      [9],
      [3,0,1],
      [8],
      [7]
    ]
    
  3. Given binary tree [3,9,8,4,0,1,7,null,null,null,2,5] (0's right child is 2 and 1's left child is 5),
         3
        /\
       /  \
       9   8
      /\  /\
     /  \/  \
     4  01   7
        /\
       /  \
       5   2
    
    return its vertical order traversal as:
    [
      [4],
      [9,5],
      [3,0,1],
      [8,2],
      [7]
    ]
    
[Thoughts]
这题挺有意思的。其实就是做一个按层遍历(http://fisherlei.blogspot.com/2013/01/leetcode-binary-tree-level-order.html),只不过在遍历的过程中,同时对于每一个节点记录其vertical index,放到map中去做统计。

[Code]

1:  /**  
2:   * Definition for a binary tree node.  
3:   * struct TreeNode {  
4:   *   int val;  
5:   *   TreeNode *left;  
6:   *   TreeNode *right;  
7:   *   TreeNode(int x) : val(x), left(NULL), right(NULL) {}  
8:   * };  
9:   */  
10:  class Solution {  
11:  public:  
12:    map<int, vector<int>> record;  
13:      
14:    vector<vector<int>> verticalOrder(TreeNode* root) {  
15:      seqOrder(root);  
16:      vector<vector<int>> result;  
17:      for(auto rec : record) {  
18:        result.push_back(rec.second);  
19:      }  
20:      return result;  
21:    }  
22:      
23:    void seqOrder(TreeNode* root) {  
24:      queue<TreeNode*> visit;  
25:      queue<int> vertical_index;  
26:        
27:      if(root == NULL) return;  
28:      visit.push(root);  
29:      vertical_index.push(0);  
30:      while(visit.size() >0) {  
31:        TreeNode* node = visit.front();  
32:        int cur_in = vertical_index.front();  
33:        visit.pop();  
34:        vertical_index.pop();  
35:          
36:        record[cur_in].push_back(node->val);  
37:          
38:        if(node->left != NULL) {  
39:          visit.push(node->left);  
40:          vertical_index.push(cur_in -1);  
41:        }  
42:          
43:        if(node->right != NULL) {  
44:          visit.push(node->right);  
45:          vertical_index.push(cur_in +1);  
46:        }  
47:      }   
48:    }  
49:  };  



Thursday, July 20, 2017

[Leetcode] Serialize and Deserialize Binary Tree, Solution

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.


[Thoughts]

这题纯粹是一道实现题,没有难点。看Code。



[Code]

1:  /**  
2:   * Definition for a binary tree node.  
3:   * struct TreeNode {  
4:   *   int val;  
5:   *   TreeNode *left;  
6:   *   TreeNode *right;  
7:   *   TreeNode(int x) : val(x), left(NULL), right(NULL) {}  
8:   * };  
9:   */  
10:  class Codec {  
11:  public:  
12:    
13:    // Encodes a tree to a single string.  
14:    string serialize(TreeNode* root) {  
15:      stringstream ss;  
16:      serializeImpl(root, ss);  
17:      return ss.str();  
18:    }  
19:    
20:    // Decodes your encoded data to tree.  
21:    TreeNode* deserialize(string data) {  
22:      std::istringstream ss(data);  
23:      return deserializeImpl(ss);  
24:    }  
25:      
26:    void serializeImpl(TreeNode* root, stringstream& ss) {  
27:      if(root == NULL) {  
28:        ss<<"#,";  
29:        return;  
30:      }  
31:        
32:      ss << root->val << ",";  
33:      serializeImpl(root->left, ss);  
34:      serializeImpl(root->right, ss);  
35:    }  
36:      
37:    TreeNode* deserializeImpl(istringstream & ss) {  
38:      std::string token;  
39:    
40:      std::getline(ss, token, ',');  
41:        
42:      if(token == "#") {  
43:        return NULL;  
44:      }  
45:        
46:      TreeNode* root = new TreeNode(stoi(token));  
47:        
48:      root->left = deserializeImpl(ss);  
49:      root->right = deserializeImpl(ss);  
50:      return root;  
51:    }  
52:      
53:      
54:  };  
55:    
56:  // Your Codec object will be instantiated and called as such:  
57:  // Codec codec;  
58:  // codec.deserialize(codec.serialize(root));  


Saturday, March 23, 2013

[LeetCode] Path Sum, Solution


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.
» Solve this problem

[Thoughts]
二叉树遍历。遍历过程中累加节点值,当到达任意叶节点的时候,进行判断。


[Code]
1:       bool hasPathSum(TreeNode *root, int sum) {  
2:            return hasPathSum(root, 0, sum);      
3:       }  
4:       bool hasPathSum(TreeNode *root, int sum, int target) {  
5:            if(root == NULL) return false;  
6:            sum += root->val;  
7:            if(root->left == NULL && root->right == NULL) //leaf  
8:            {  
9:                 if(sum == target)  
10:                      return true;  
11:                 else  
12:                      return false;  
13:            }  
14:            return hasPathSum(root->left, sum, target)   
15:                   || hasPathSum(root->right, sum, target);      
16:       }  











Friday, March 22, 2013

[Interview] Serialize and De-serialize a tree

A very frequent interview question. Suppose you have a tree, how could you serialize it to file and revert it back?


for example,

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

[Thoughts]
一个比较简单直接的做法是,通过前序遍历来做,把所有空节点当做“#”来标示。那么这棵树可以表示为

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

那么前序遍历的结果就是: {'1','2','#','4','6','#','#','7','#','#','3','5','#','#','#'}; 代码如下:


void Serialize(TreeNode * node, vector<char> &output)
{
       if(node == NULL)
       {
             output.push_back('#');
             return;
       }

       output.push_back(node->val + '0');
       Serialize(node->left, output);
       Serialize(node->right, output);
}

而反序列化的代码也就是:

TreeNode *Deserialize(vector<char> output, int &index)
{
       if(index > output.size() || output[index] == '#') return NULL;

       TreeNode *node = new TreeNode(output[index] -'0');
       index ++;
       node->left = Deserialize(output, index);
       index++;
       node->right = Deserialize(output, index);
       return node;
}



这里只能通过前序遍历来做,中序及后序是行不通的。原因很简单,除了前序以外,其他遍历方式没办法找出头结点。

除了常规的三种遍历方式意外, 另一种可行的方法就是按层来遍历,同样可行。










[LeetCode] Convert Sorted Array to Binary Search Tree, Solution


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

[Thoughts]
If we build BST from array, we can build it from top to bottom, like
1. choose the middle one as root,
2. build left sub BST via left part array
3. build right sub BST via right part array
4. do this recursively.



[Code]
1:       TreeNode *sortedArrayToBST(vector<int> &num) {  
2:            return BuildTree(num, 0, num.size()-1);  
3:       }  
4:       TreeNode *BuildTree(vector<int> &num, int start, int end)  
5:       {  
6:            if(start>end) return NULL;  
7:            if(start == end) return new TreeNode(num[start]);  
8:            int mid = (start+end)/2;  
9:            TreeNode *node = new TreeNode(num[mid]);  
10:           node->left = BuildTree(num, start, mid-1);  
11:           node->right = BuildTree(num, mid+1, end);  
12:           return node;  
13:       }  




Wednesday, March 20, 2013

[LeetCode] Unique Binary Search Trees, Solution


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
» Solve this problem

[Thoughts]
这题想了好久才想清楚。其实如果把上例的顺序改一下,就可以看出规律了。
 1                1                      2                       3             3
    \                 \                 /      \                  /              /
      3               2              1       3               2             1
    /                   \                                       /                  \
 2                       3                                   1                    2

比如,以1为根的树有几个,完全取决于有二个元素的子树有几种。同理,2为根的子树取决于一个元素的子树有几个。以3为根的情况,则与1相同。

定义Count[i] 为以[0,i]能产生的Unique Binary Tree的数目,

如果数组为空,毫无疑问,只有一种BST,即空树,
Count[0] =1

如果数组仅有一个元素{1},只有一种BST,单个节点
Count[1] = 1

如果数组有两个元素{1,2}, 那么有如下两种可能
1                       2
  \                    /
    2                1
Count[2] = Count[0] * Count[1]   (1为根的情况)
                  + Count[1] * Count[0]  (2为根的情况。

再看一遍三个元素的数组,可以发现BST的取值方式如下:
Count[3] = Count[0]*Count[2]  (1为根的情况)
               + Count[1]*Count[1]  (2为根的情况)
               + Count[2]*Count[0]  (3为根的情况)

所以,由此观察,可以得出Count的递推公式为
Count[i] = ∑ Count[0...k] * [ k+1....i]     0<=k<i-1
问题至此划归为一维动态规划。

[Code]
1:       int numTrees(int n) {  
2:            vector<int> count(n+1, 0);  
3:            count[0] =1;  
4:            count[1] =1;  
5:            for(int i =2; i<=n; i++)  
6:            {  
7:                 for(int j =0; j<i; j++)  
8:                 {  
9:                      count[i] += count[j]*count[i-j-1];   
10:                 }  
11:            }  
12:            return count[n];  
13:       }  


[Note]
这是很有意思的一个题。刚拿到这题的时候,完全不知道从那下手,因为对于BST是否Unique,很难判断。最后引入了一个条件以后,立即就清晰了,即
当数组为 1,2,3,4,.. i,.. n时,基于以下原则的BST建树具有唯一性:
以i为根节点的树,其左子树由[0, i-1]构成, 其右子树由[i+1, n]构成。



Friday, February 22, 2013

[LeetCode] Sum Root to Leaf Numbers, Solution


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.
» Solve this problem


[Thoughts]
Recursion. Similar as [LeetCode] Binary Tree Maximum Path Sum Solution, the difference here is only adding a track variable to sum all the paths.

[Code]
1:       int sumNumbers(TreeNode *root) {  
2:            int sum=0, path =0;            
3:            GenerateSum(root, sum, path);  
4:            return sum;  
5:       }  
6:       void GenerateSum(TreeNode *root, int& sum, int path)  
7:       {  
8:            if(root == NULL) return;      
9:            path = path*10 +root->val;  
10:            if(root->left == NULL && root->right == NULL)  
11:            {  
12:                 sum+=path;  
13:                 return;  
14:            }  
15:            GenerateSum(root->left, sum, path);  
16:            GenerateSum(root->right, sum, path);  
17:       }  










Saturday, February 2, 2013

[Google] Inorder Successor in Binary Search Tree, Solution


In Binary Tree, Inorder successor of a node is the next node in Inorder traversal of the Binary Tree. Inorder Successor is NULL for the last node in Inoorder traversal.
In Binary Search Tree, Inorder Successor of an input node can also be defined as the node with the smallest key greater than the key of input node. So, it is sometimes important to find next node in sorted order.

In the above diagram, inorder successor of 8 is 10, inorder successor of 10 is 12 and inorder successor of 14 is 20.
Method 1 (Uses Parent Pointer)
In this method, we assume that every node has parent pointer.
The Algorithm is divided into two cases on the basis of right subtree of the input node being empty or not.
Input: node, root // node is the node whose Inorder successor is needed.
output: succ // succ is Inorder successor of node.
1) If right subtree of node is not NULL, then succ lies in right subtree. Do following.
Go to right subtree and return the node with minimum key value in right subtree.
2) If right sbtree of node is NULL, then succ is one of the ancestors. Do following.
Travel up using the parent pointer until you see a node which is left child of it’s parent. The parent of such a node is the succ.
Implementation
Note that the function to find InOrder Successor is highlighted (with gray background) in below code.
1:  #include <stdio.h>  
2:  #include <stdlib.h>  
3:  /* A binary tree node has data, pointer to left child  
4:    and a pointer to right child */  
5:  struct node  
6:  {  
7:    int data;  
8:    struct node* left;  
9:    struct node* right;  
10:    struct node* parent;  
11:  };  
12:  struct node * minValue(struct node* node);  
13:  struct node * inOrderSuccessor(struct node *root, struct node *n)  
14:  {  
15:   // step 1 of the above algorithm  
16:   if( n->right != NULL )  
17:    return minValue(n->right);  
18:   // step 2 of the above algorithm  
19:   struct node *p = n->parent;  
20:   while(p != NULL && n == p->right)  
21:   {  
22:     n = p;  
23:     p = p->parent;  
24:   }  
25:   return p;  
26:  }  
27:  /* Given a non-empty binary search tree, return the minimum data   
28:    value found in that tree. Note that the entire tree does not need  
29:    to be searched. */  
30:  struct node * minValue(struct node* node) {  
31:   struct node* current = node;  
32:   /* loop down to find the leftmost leaf */  
33:   while (current->left != NULL) {  
34:    current = current->left;  
35:   }  
36:   return current;  
37:  }  
Time Complexity: O(h) where h is height of tree.


Method 2 (Don't Use Parent Pointer)
Inorder travel the tree and
1) If current visit node is target node,  mark the indicator as true.
2) If indicator is true, print the node and return.

Implementation
1:  struct node * inOrderSuccessor(struct node *n, struct node* target, bool& indicator)  
2:  {  
3:   if( n== NULL )  
4:    return NULL;  
5:   if(indicator) return n;  
6:   if(n == target) { indicator = true; return;}  
7:   node* left = inOrderSuccessor(n->left, target, indicator);  
8:   node * right =inOrderSuccessor(n->right, target, indicator);  
9:   if(left != NULL) return left;  
10:   if(right!= NULL) return right;  
11:   return NULL;  
12:  }  

Friday, December 21, 2012

[LeetCode] 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
» Solve this problem


[解题思路]
递归解法。对于任一节点,flatten左树,然后节点插入左树最左边,成为新的头节点。flatten右树,右树最左边接上新链表的最右节点。


[Code]
1:  void flatten(TreeNode *root) {  
2:       // Start typing your C/C++ solution below  
3:       // DO NOT write int main() function  
4:       if(root == NULL)  
5:            return;  
6:       ConvertToLink(root);  
7:  }  
8:  TreeNode* ConvertToLink(TreeNode* node)  
9:  {  
10:       if(node->left == NULL && node->right == NULL)  
11:            return node;  
12:       TreeNode* rHead = NULL;  
13:       if(node->right != NULL)  
14:           rHead = ConvertToLink(node->right);               
15:       TreeNode* p = node;  
16:       if(node->left!=NULL)  
17:       {  
18:            TreeNode* lHead = ConvertToLink(node->left);   
19:            node->right = lHead;  
20:            lHead->left = NULL;  
21:            node->left = NULL;  
22:            while(p->right!=NULL)  
23:                 p = p->right;  
24:       }       
25:       if(rHead != NULL)  
26:       {  
27:            p->right = rHead;  
28:            rHead->left = NULL;  
29:       }  
30:       return node;  
31:  }  

[已犯错误]
1. Line 13~14
    刚开始的时候,首先flatten左树,然后处理右树。但是这样会导致处理右树的时候,节点的值已经在处理树的时候被破坏了。比如树为{1,2,3},
     1
  /     \
2       3
如果先处理左树的话,当执行node->right = lhead的时候,右节点就已经被破坏了,node->right指向了2,而不是3。
1
   \
     2  (3)
当然,也可以用一个变量在处理左树前,保存右树地址。但是没必要,先处理右树就好了。
2. Line 22~23
    该循环是用于将p指针遍历到左树链表的最右节点。第一版时,这个循环是放在if语句以外,这就导致了,不必要的迭代了。比如当输入为{1,#,2}时,这个while循环会导致p指针遍历到右子树的最右节点,这显然是错的。
3. Line 20, 28
    不要忘了清空每一个指针,在新的链表中,左指针没必要保留。



Update 08/25/2014  being asked this question today. But the interviewer asked for an in-order flatten.
Review previous solution. Actually, I made it too complicate. If travel this tree in pre-order, from the hint, it is easy to construct the linked list.

1:       void flatten(TreeNode *root) {  
2:            if(root == NULL) return;  
3:            TreeNode* right = root->right;  
4:            if(lastVisitedNode != NULL)  
5:            {  
6:                 lastVisitedNode->left = NULL;  
7:                 lastVisitedNode->right = root;  
8:            }  
9:            lastVisitedNode = root;  
10:            flatten(root->left);  
11:            flatten(right);  
12:       }  

pre-order is simple because the root always is the head of flatten list. But if flatten the tree with in-order sequence, need extra parameter to track the head and tail of each flattened sun-tree.
For example, below binary tree.

If we flatten it with in-order, the process should like below. And here I use the left pointer of head node to track the tail node.



1:  TreeNode* flatten(TreeNode *root) {  
2:       if (root == NULL) return NULL;  
3:       TreeNode* rightTree = root->right;  
4:       TreeNode* newHead = root;  
5:       TreeNode* leftList = flatten(root->left);  
6:       if (leftList != NULL)  
7:       {  
8:            newHead = leftList;  
9:            TreeNode* tail = leftList->left;  
10:            tail->right = root;  
11:            root->left = tail;  
12:            leftList->left = root;  
13:       }  
14:       TreeNode* rightList = flatten(rightTree);  
15:       if (rightList != NULL)  
16:       {  
17:            root->right = rightList;  
18:            newHead->left = rightList->left;  
19:            rightList->left = root;  
20:       }  
21:       return newHead;  
22:  }