Showing posts with label BST. Show all posts
Showing posts with label BST. Show all posts

Wednesday, August 17, 2016

333. Largest BST Subtree

I can use the way that "98. Validate Binary Search Tree" does to validate if the root is a valid BST root. If it is, then just count the node in the BST. Otherwise, do the same to its left subtree and right subtree.

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:    int largestBSTSubtree(TreeNode* root) {  
13:      if (root == NULL) return 0;  
14:      if (root->left == NULL && root->right == NULL) return 1;  
15:      if (isValidBST(root, NULL, NULL)) return count(root);  
16:      return max(largestBSTSubtree(root->left), largestBSTSubtree(root->right));  
17:    }  
18:    bool isValidBST(TreeNode *root, TreeNode *pre, TreeNode *suc) {  
19:      if (root == NULL) return true;  
20:      if (pre && root->val <= pre->val) return false;  
21:      if (suc && root->val >= suc->val) return false;  
22:      return isValidBST(root->left, pre, root) && isValidBST(root->right, root, suc);  
23:    }  
24:    int count(TreeNode *root) {  
25:      if (root == NULL) return 0;  
26:      if (root->left == NULL && root->right == NULL) return 1;  
27:      return 1 + count(root->left) + count(root->right);  
28:    }  
29:  };  

The solution above is a top-down one. The top rated solution which follows a down-top way runs at O(n) time since each node only need to be visited once. Will investigate later.

Sunday, August 14, 2016

285. Inorder Successor in BST

It's very easy to miss the case that when we go into left subtree, current root become the successor.

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:    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {  
13:      TreeNode *successor = NULL;  
14:      while (root) {  
15:        if (root->val == p->val) {  
16:          if (root->right == NULL) return successor;  
17:          else {  
18:            root = root->right;  
19:            while (root->left) root = root->left;  
20:            return root;  
21:          }  
22:        } else if (root->val < p->val) {  
23:          root = root->right;  
24:        } else {  
25:          successor = root;  
26:          root = root->left;  
27:        }  
28:      }  
29:      return NULL;  
30:    }  
31:  };  

255. Verify Preorder Sequence in Binary Search Tree

I was trying divide and conquer solution as following but got TLE.

1:  class Solution {  
2:  public:  
3:    bool verifyPreorder(vector<int>& preorder) {  
4:      if (preorder.empty()) return true;  
5:      return helper(preorder, 0, preorder.size()-1);  
6:    }  
7:    bool helper(vector<int> &preorder, int s, int e) {  
8:      if (s >= e) return true;  
9:      int pivot = preorder[s];  
10:      int bigger = -1;  
11:      for (int i = s+1; i <= e; i++) {  
12:        if (bigger == -1 && preorder[i] > pivot) bigger = i;  
13:        if (bigger != -1 && preorder[i] < pivot) return false;  
14:      }  
15:      if (bigger == -1) {  
16:        return helper(preorder, s+1, e);  
17:      } else {  
18:        return helper(preorder, s+1, bigger-1) && helper(preorder, bigger, e);  
19:      }  
20:    }  
21:  };  

Then I have to follow the top rated solution which uses stack. The idea is to traverse the list and use a stack to store all predecessors. As long as the stack's top node is less than the current list node, we can assume that the current list node is a predecessor and push it to the stack. Once we meet a node that is larger than the top node, we know we are going to enter the right subtree and we need to pop out all the predecessors that are less than current list node but keep the last predecessor. And then we push the current list node into stack and we enters the right subtree. Note for the right subtree, all the node must be larger than the last predecessor, if not then we conclude that it is an invalid preorder sequence in BST.

1:  class Solution {  
2:  public:  
3:    bool verifyPreorder(vector<int>& preorder) {  
4:      if (preorder.size() < 2) return true;  
5:      stack<int> stk;  
6:      stk.push(preorder[0]);  
7:      int last = INT_MIN;  
8:      for (int i = 1; i < preorder.size(); i++) {  
9:        if (stk.empty() || preorder[i] < stk.top()) {  
10:          if (preorder[i] < last) return false;  
11:          stk.push(preorder[i]);  
12:        } else {  
13:          while (!stk.empty() && stk.top() < preorder[i]) {  
14:            last = stk.top();  
15:            stk.pop();  
16:          }  
17:          stk.push(preorder[i]);  
18:        }  
19:      }  
20:      return true;  
21:    }  
22:  };  

Wednesday, August 10, 2016

108. Convert Sorted Array to Binary Search Tree

Well, not much to say. Pretty straightforward DFS solution.

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:    TreeNode* sortedArrayToBST(vector<int>& nums) {  
13:      int n = nums.size();  
14:      return helper(nums, 0, n-1);  
15:    }  
16:    TreeNode *helper(vector<int> &nums, int s, int e) {  
17:      if (s > e) return NULL;  
18:      int mid = s + (e - s) / 2;  
19:      TreeNode *node = new TreeNode(nums[mid]);  
20:      node->left = helper(nums, s, mid-1);  
21:      node->right = helper(nums, mid+1, e);  
22:      return node;  
23:    }  
24:  };  

Thursday, August 4, 2016

235. Lowest Common Ancestor of a Binary Search Tree

Well, a quite easy problem.

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:    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {  
13:      if (root->val > p->val && root->val > q->val) return lowestCommonAncestor(root->left, p, q);  
14:      if (root->val < p->val && root->val < q->val) return lowestCommonAncestor(root->right, p, q);  
15:      return root;  
16:    }  
17:  };  

Thursday, July 21, 2016

173. Binary Search Tree Iterator

This is actually a iterative traversal of BST by the help of stack.

1:  /**  
2:   * Definition for binary tree  
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 BSTIterator {  
11:  private:  
12:    stack<TreeNode *> stk;  
13:  public:  
14:    BSTIterator(TreeNode *root) {  
15:      while (root) {  
16:        stk.push(root);  
17:        root = root->left;  
18:      }  
19:    }  
20:    /** @return whether we have a next smallest number */  
21:    bool hasNext() {  
22:      return !stk.empty();  
23:    }  
24:    /** @return the next smallest number */  
25:    int next() {  
26:      TreeNode *t = stk.top();  
27:      stk.pop();  
28:      if (t->right) {  
29:        TreeNode *p = t->right;  
30:        while (p) {  
31:          stk.push(p);  
32:          p = p->left;  
33:        }  
34:      }  
35:      return t->val;  
36:    }  
37:  };  
38:  /**  
39:   * Your BSTIterator will be called like this:  
40:   * BSTIterator i = BSTIterator(root);  
41:   * while (i.hasNext()) cout << i.next();  
42:   */  

Friday, July 15, 2016

270. Closest Binary Search Tree Value

Binary search. We should note that for BST to find place for a new node to insert, we must reach a NULL pointer. So the termination for binary search in BST is either the left or the right child node that we are ready to move to becomes NULL. We only need to compare the root node with the closest node in its subtree in order to get the right one.

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:    int closestValue(TreeNode* root, double target) {  
13:      int a = root->val;  
14:      TreeNode *child = target < a ? root->left : root->right;  
15:      if (child == NULL) return a;  
16:      int b = closestValue(child, target);  
17:      return abs(a - target) < abs(b - target) ? a : b;  
18:    }  
19:  };  

99. Recover Binary Search Tree

My initial idea is to output all nodes into an array. Since it is a binary search tree, an in-order traversal should get us a sorted array. All we need to do then is to find two nodes that are out of order and swap then. The easy mistake to make is to use if else clause in finding the two node. Note these two nodes are not exclusive to each other, so we shouldn't do "else".

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:  private:  
12:    vector<TreeNode*> res;  
13:  public:  
14:    void recoverTree(TreeNode* root) {  
15:      helper(root);  
16:      TreeNode *first = NULL, *second = NULL;  
17:      for (int i = 0; i < res.size()-1; i++) {  
18:        if (first == NULL && res[i]->val > res[i+1]->val) {  
19:          first = res[i];  
20:        }  
21:        if (first != NULL && res[i]->val > res[i+1]->val) {  
22:          second = res[i+1];  
23:        }  
24:      }  
25:      swap(first->val, second->val);  
26:    }  
27:    void helper(TreeNode* root) {  
28:      if (root == NULL) return;  
29:      helper(root->left);  
30:      res.push_back(root);  
31:      helper(root->right);  
32:    }  
33:  };  

There is another way to find out the two out-of-order nodes within the in-order traversal. It's very important to let the previous node be a global variable. Because when you are traversing left child, when you are done, you want the previous node to be the left child. If you pass the previous node to the recursion, you are only considering the case of right child.

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:  private:  
12:    TreeNode *first = NULL;  
13:    TreeNode *second = NULL;  
14:    TreeNode *prev = new TreeNode(INT_MIN);  
15:  public:  
16:    void recoverTree(TreeNode* root) {  
17:      helper(root);  
18:      swap(first->val, second->val);  
19:    }  
20:    void helper(TreeNode *root) {  
21:      if (root == NULL) return;  
22:      helper(root->left);  
23:      if (first == NULL && prev->val >= root->val) first = prev;  
24:      if (first != NULL && prev->val >= root->val) second = root;  
25:      prev = root;  
26:      helper(root->right);  
27:    }  
28:  };  

Thursday, July 7, 2016

315. Count of Smaller Numbers After Self

The problem can be restated in this way, find the inverse numbers (i.e. nums[i] > nums[j] but i < j) for each number in the array. There are two ways to solve this problem. First solution is to build a binary search tree from the end to beginning such that a new coming node must have index less than existing node. So the invert number for the new node will be nodes that have value less than it. To do so, we need to modify the tree node a little bit to include left node count and its own copy (for duplicate nodes). So for a new coming number, there are 3 cases:

Case 1: root value is equal to the new value, i.e. a duplicated node is found.
We just increase the root's copy and return the left count of root.

Case 2: root value is less than the new value.
We need to increase the left count of root and insert the new node to left and return the new node's left count.

Case 3: root value is larger than the new value.
We need to insert the new node to right and return root's left count plus root's own copy plus the new node's left count.

From the three cases above, we can see that we need to return the left count for insert operation.

1:  class Node {  
2:  public:  
3:    int val, copy, leftCount;  
4:    Node *left, *right;  
5:    Node(int x) { val = x; copy = 1; leftCount = 0; left = NULL; right = NULL; }  
6:  };  
7:  class Solution {  
8:  public:  
9:    vector<int> countSmaller(vector<int>& nums) {  
10:      int n = nums.size();  
11:      vector<int> res(n, 0);  
12:      if (nums.size() <= 1) return res;  
13:      Node *root = new Node(nums[nums.size()-1]);  
14:      for (int i = nums.size()-2; i >= 0; i--) {  
15:        res[i] = insert(root, nums[i]);  
16:      }  
17:      return res;  
18:    }  
19:    int insert(Node *root, int val) {  
20:      if (root->val == val) {  
21:        root->copy++;  
22:        return root->leftCount;  
23:      } else if (root->val > val) {  
24:        root->leftCount++;  
25:        if (root->left) {  
26:          return insert(root->left, val);  
27:        } else {  
28:          root->left = new Node(val);  
29:          return 0;  
30:        }  
31:      } else {  
32:        if (root->right) {  
33:          return root->leftCount+root->copy+insert(root->right, val);  
34:        } else {  
35:          root->right = new Node(val);  
36:          return root->leftCount+root->copy;  
37:        }  
38:      }  
39:    }  
40:  };  

When I revisited this problem, I made mistakes in:
line 16: I was returning 1 instead of 0.
line 27: I wasn't aware that there is no smaller number if the input array only contains one number.
line 29: I wasn't aware that I should have started from the end.

1:  class MyTreeNode {  
2:  public:  
3:    int val;  
4:    int copy;  
5:    int leftCounts;  
6:    MyTreeNode *left;  
7:    MyTreeNode *right;  
8:    MyTreeNode(int x): val(x), copy(1), leftCounts(0), left(NULL), right(NULL) {}  
9:  };  
10:  class Solution {  
11:  private:  
12:    int insert(MyTreeNode *root, int val) {  
13:      if (root->val == val) { root->copy++; return root->leftCounts; }  
14:      if (root->val > val) {   
15:        root->leftCounts++;  
16:        if (root->left == NULL) { root->left = new MyTreeNode(val); return 0;}  
17:        else return insert(root->left, val);  
18:      } else {  
19:        if (root->right == NULL) { root->right = new MyTreeNode(val); return root->leftCounts + root->copy; }  
20:        else return root->leftCounts + root->copy + insert(root->right, val);  
21:      }  
22:    }  
23:  public:  
24:    vector<int> countSmaller(vector<int>& nums) {  
25:      int n = nums.size();  
26:      vector<int> res = vector<int>(n, 0);  
27:      if (n < 2) return res;  
28:      MyTreeNode *root = new MyTreeNode(nums[n-1]);  
29:      for (int i = n-2; i >= 0; i--) {  
30:        res[i] = insert(root, nums[i]);  
31:      }  
32:      return res;  
33:    }  
34:  };  

Another way is to do merge sort.

Tuesday, June 28, 2016

98. Validate Binary Search Tree

In first place, I made a mistake that I only recursively compare the parent with its left and right child. This is incorrect. Note for a BST, all the nodes left child subtree are less than the root and on the other hand, all the nodes in right child subtree are larger than the root. Therefore, when doing the recursive call, we need to compare the current node with a minimal node and a maximal node. For the left subtree, the maximal node is the current node and for the right subtree, the minimal node is the current node. Also, the recursive function follows inorder traversal.

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:    bool isValidBST(TreeNode* root) {  
13:      return helper(root, NULL, NULL);  
14:    }  
15:    bool helper(TreeNode *root, TreeNode *minNode, TreeNode *maxNode) {  
16:      if (root == NULL) return true;  
17:      if (minNode && root->val <= minNode->val || maxNode && root->val >= maxNode->val) {  
18:        return false;  
19:      }  
20:      return helper(root->left, minNode, root) && helper(root->right, root, maxNode);  
21:    }  
22:  };  

Saturday, June 25, 2016

109. Convert Sorted List to Binary Search Tree

The intuitive idea is to recursively construct binary search tree. There are two ways. First solution is using a counter.

1:  class Solution {  
2:  public:  
3:    TreeNode* sortedListToBST(ListNode* head) {  
4:      int len = 0;  
5:      ListNode *cur = head;  
6:      while (cur) {  
7:        len++;  
8:        cur = cur->next;  
9:      }  
10:      return helper(head, len);  
11:    }  
12:    TreeNode *helper(ListNode* head, int len) {  
13:      if (len == 0) return NULL;  
14:      int half = len / 2;  
15:      ListNode *cur = head;  
16:      for (int i = 0; i < half; i++) {  
17:        cur = cur->next;  
18:      }  
19:      TreeNode *node = new TreeNode(cur->val);  
20:      TreeNode *left = helper(head, half);  
21:      TreeNode *right = helper(cur->next, len-half-1);  
22:      node->left = left;  
23:      node->right = right;  
24:      return node;  
25:    }  
26:  };  

The second solution uses slow and fast pointer to find the middle node. This is a little bit faster than the first one because it saves one entire list scan.

1:  class Solution {  
2:  public:  
3:    TreeNode* sortedListToBST(ListNode* head) {  
4:      if (head == NULL) return NULL;  
5:      ListNode *slow = head, *fast = head, *prev = NULL;  
6:      while (fast && fast->next) {  
7:        prev = slow;  
8:        slow = slow->next;  
9:        fast = fast->next->next;  
10:      }  
11:      if (prev == NULL) head = NULL;  
12:      else prev->next = NULL;  
13:      TreeNode *node = new TreeNode(slow->val);  
14:      node->left = sortedListToBST(head);  
15:      node->right = sortedListToBST(slow->next);  
16:      return node;  
17:    }  
18:  };  

Wednesday, June 22, 2016

230. Kth Smallest Element in a BST

My original solution is to traverse the tree in preorder and save the result in an array. Return the k-th number in the array.

1:  class Solution {  
2:  public:  
3:    int kthSmallest(TreeNode* root, int k) {  
4:      vector<int> res;  
5:      helper(root, res);  
6:      return res[k-1];  
7:    }  
8:    void helper(TreeNode* root, vector<int> &res) {  
9:      if (root == NULL) return;  
10:      helper(root->left, res);  
11:      res.push_back(root->val);  
12:      helper(root->right, res);  
13:    }  
14:  };  

Another way is to count the left nodes and use binary search to get the k-th number. However, this is not an optimal solution whose running time is O(NlogN). If we can modify augment the TreeNode data structure and keep track its left child numbers when building the tree, we can achieve the search by O(logN).

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:    int kthSmallest(TreeNode* root, int k) {  
13:      int c = countNodes(root->left);  
14:      if (c == k-1) return root->val;   
15:      if (c < k-1) {  
16:        return kthSmallest(root->right, k-c-1);  
17:      } else {  
18:        return kthSmallest(root->left, k);  
19:      }  
20:    }  
21:    int countNodes(TreeNode *root) {  
22:      if (root == NULL) return 0;  
23:      return 1 + countNodes(root->left) + countNodes(root->right);  
24:    }  
25:  };