Algorithm Design Book - Chapter 3
LeetCode
-
Count of Smaller Numbers After Self
We have to see how many numbers are smaller to self on the right.
Naive: Just interate for each element and check how many elements are smaller on the right for a given index - \(O(n^2)\)
Merge Sort : Posting an example for more clarity
void MergeSort(vector<int> &nums, vector<int> &indices, vector<int> &results, int start, int end){ int count = end-start; if(count > 1){ int mid = start + count/2; MergeSort(nums,indices, results, start, mid); MergeSort(nums, indices, results, mid, end); vector<int> tmp; tmp.reserve(count); int idx1 = start, idx2 = mid; int smallcount=0; while(idx1 < mid || idx2 < end){ if((idx2 == end) || (idx1 < mid && nums[indices[idx1]] <= nums[indices[idx2]])){ tmp.push_back(indices[idx1]); results[indices[idx1]] += smallcount; idx1++; } else{ tmp.push_back(indices[idx2++]); smallcount++; } } move(tmp.begin(), tmp.end(), indices.begin()+start); } }
Two approaches:
- Recursive: Here we keep adding preorder entries into a tree. To differentiate b/w entries which will be in left/right subtree is done on the basis of Inorder vector. Seems \(O(n^2)\) as we need to find the inorder entry idx for each preorder idx.
private:
TreeNode* build(vector<int> &preorder, vector<int>& inorder, int start, int end, int& idx){
if(start > end){
return NULL;
}
TreeNode* node = new TreeNode(preorder[idx++]);
int it = find(inorder.begin()+start, inorder.end(), preorder[idx-1]) - inorder.begin();
node->left = build(preorder, inorder, start, it-1, idx);
node->right = build(preorder, inorder, it+1, end, idx);
return node;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int idx=0;
return build(preorder, inorder, 0, inorder.size()-1, idx);
}
-
Stack : This is new for me. \(O(n)\). Here is the initution:
We know that preorder transversal is as follows:
- node
- node->left
- node->right
So we always transverse a left node in preorder until there are none left(I hope you got the pun). How do we know that there is no left subtree after a point? Answer from Inorder transversal
The inorder transversal can be shown as follows:
- node->left
- node
- node->right
so We store the left most node of the tree in the beginning. then the second most and the list goes on. so what we can do is:
- Make a stack of nodes with the first entry as preorder[0]
- Keep assuming that the next entry is a left child until the top of the stack matches the inorder[0]. this means we have reached the left mode node
- now pop the stack until we have s.top() == inorder[j] or s.empty().
- Once this is done, we can see that the left most node of the remaining tree is part of the right subtree of the node.
- So we will assign the next node as right child.
- to keep track of the right child we can keep a flag which resets after assigning the next node as right child.
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(!preorder.size())
return NULL;
stack<TreeNode*> st;
TreeNode* root = new TreeNode(preorder[0]);
st.push(root);
int i=1, j=0, flag=0;
TreeNode* t = root;
while(i < preorder.size()){
if(!st.empty() && st.top()->val == inorder[j]){
t = st.top();
flag = 1;
st.pop();
j++;
}
else{
if(flag){
flag=0;
t->right = new TreeNode(preorder[i++]);
t = t->right;
st.push(t);
}
else{
t->left = new TreeNode(preorder[i++]);
t = t->left;
st.push(t);
}
}
}
return root;
}