Find kth min node in AVL tree - algorithm

I now have built a AVL tree, Here is a function to find kth min node in AVL tree
(k started from 0)
Code:
int kthMin(int k)
{
int input=k+1;
int count=0;
return KthElement(root,count,input);
}
int KthElement( IAVLTreeNode * root, int count, int k)
{
if( root)
{
KthElement(root->getLeft(), count,k);
count ++;
if( count == k)
return root->getKey();
KthElement(root->getRight(),count,k);
}
return NULL;
}
It can find some of right nodes, but some may fail, anyone can help me debug this>
THanks

From the root, after recursing left, count will be 1, regardless of how many nodes are on the left.
You need to change count in the recursive calls, so change count to be passed by reference (assuming this is C++).
int KthElement( IAVLTreeNode * root, int &count, int k)
(I don't think any other code changes are required to get pass by reference to work here).
And beyond that you need to actually return the value generated in the recursive call, i.e. change:
KthElement(root->getLeft(), count, k);
to:
int val = KthElement(root->getLeft(), count, k);
if (val != 0)
return val;
And similarly for getRight.
Note I used 0, not NULL. NULL is typically used to refer to a null pointer, and it converts to a 0 int (the latter is preferred when using int).
This of course assumes that 0 isn't a valid node in your tree (otherwise your code won't work). If it is, you'll need to find another value to use, or a pointer to the node instead (in which case you can use NULL to indicate not found).

Here is simple algorithm for Kth smallest node in any tree in general:-
count=0, found=false;
kthElement(Node p,int k) {
if(p==NULL)
return -1
else {
value = kthElement(p.left)
if(found)
return value
count++
if(count==k) {
found = true
return p.value
}
value = kthElement(p.right)
return value
}
}
Note:- Use of global variables is the key.

Related

Improving this binary tree algorithm complexity

I need to find if all paths of a binary tree that can end(which means all paths that starts from the root and end to a node that has only one child or none) have lengths that differ by no more than one.
My working solution work like this: the function longestPath finds the longest path, the function checkLengths traverse all nodes keeping track of the length of the paths and every time a node with only one child or none is found it checks if the difference between the length of the current path and the length of the longest path is more than 1.
This solution has complexity O(2n) because at worst every node has to be visited twice, once for the longestPath function and once for the lengthCheck function. I would like to improve the solution to O(n) but I'm having an hard time figuring out how to do so.
Edit: my solution is still O(n) but I would like to optimize it to find the solution by visiting each node only once and not twice.
int lengthCheckFlag=1;
int maxLength=-1;
void longestPath(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxLength==-1){
maxLength=currentLength;
}
else{
if(currentLength>maxLength){
maxLength=currentLength;
}
}
}
longestPath(n->left,currentLength+1);
longestPath(n->right,currentLength+1);
}
void checkLengths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr || n->right==nullptr){
if(abs(maxLength-currentLength)>1){
lengthCheckFlag=0;
}
}
checkLengths(n->left,currentLength+1);
checkLengths(n->right,currentLength+1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
longestPath(n,0);
checkLengths(n,0);
return lengthCheckFlag;
}
Code Update:
int maxP=-1;
int minP=-1;
void minmaxPaths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxP==-1){
maxP=currentLength;
minP=currentLength;
}
else{
if(currentLength>maxP){
maxP=currentLength;
}
if(currentLength<minP){
minP=currentLength;
}
}
}
minmaxPaths(n->left,currentLength+1);
minmaxPaths(n->right,currentLength+1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
minmaxPaths(n,0);
if(abs(minP-maxP)<=1){
return true;
}
return false;
}
Some remarks:
O(2n) is the same as O(n)
Your functions use different conditions for identifying the potential end of a path: one uses a && operator (wrong) and the other uses a || operator (correct)
One idea for an alternative algorithm is to make a breadth first traveral. This is interesting, since the constraint really means that all non-perfect nodes (i.e. that have at most one child) must appear in the bottom two levels of the tree.
By consequence, if we find 2 more levels after the first level where we find a non-perfect node, then we have a violation and can stop the traversal.
The down side is that it uses more memory.
Here is how it could be implemented:
int minmaxDepth(Node root) {
if (root == nullptr) {
return 1; // OK
}
std::vector<Node> level, nextLevel;
level.push_back(root);
int minDepth = INT_MAX;
int currDepth = 0;
while (level.size()) {
currDepth++;
nextLevel = {};
for (auto & parent : level) {
if (currDepth < minDepth &&
(parent->left == nullptr || parent->right == nullptr)) {
minDepth = currDepth; // Found a path with minimal length
}
if (parent->left != nullptr) {
nextLevel.push_back(parent->left);
}
if (parent->right != nullptr) {
nextLevel.push_back(parent->right);
}
if (nextLevel.size() && currDepth > minDepth) {
return 0; // Paths have lengths that differ more than 1
}
}
level = nextLevel;
}
return 1; // All nodes were visited: no violation found
}
There is no need to pre-compute the longest path. Compute all path lengths and on the fly,
store the first length,
if some other length differs by more than one, you are done;
else store the differing length, and if any other length differs from the two stored ones, you are done.

Returning an element with a specific rank k in a binary tree

I already implemented a method rankOfElement(x) in pseudocode which returns the rank for a given node x:
function rankofElement(x) {
rank = 0;
Node temp = root;
while (temp.key != x) {
if (x < temp.key) {
temp = temp.leftson
} else if (x > temp.key) {
rank += temp.leftson.size + 1;
temp = temp.rightson;
} else if (temp.key == x) {
return rank + temp.leftson.size
} else return "key not found"
}
Now I should implement a method (elementbyRank(k)) in pseudocode which returns a node with a specific rank k in the context of a binary tree.
I am struggling with that and I hope you can give me an answer.
So, if given rank k and we need to find a node with the given rank we first need a traversal algorithm to search through the tree. A pre-order traversal should work just fine. Here is a recursive one.
function preOrderTraversal(node){
if(node !== null){
print(node.data);
preOrderTraversal(node.left);
preOrderTraversal(node.right);
}
}
now that we have a way to get through our tree we need to implement the elementbyRank method and modify the traversal algorithm. Instead of printing the data we will check each node's rank. we will need to pass rank we need to find and we will need to add a return to the traversal.
The elementbyRank method is pretty simple:
function elementbyRank(k){
return preOrderTraversal(root, k);
}
Now we need to make the changes to the prePrderTraveral and let's change the name as well to elementbyRankTraversal.
function elementbyRankTraversal(node, key){
if(node !== null){
if(key == rankofElement(node.key))
return node;
return elementbyRankTraversal(node.left);
return elementbyRankTraversal(node.right);
}
return null;
}
So now if we find a node with the passed in rank, we will get that node back. but if one does not exist we will instead get a null value.
I know that you said given node x, the rankofElement(x) will return the rank of the element. but you are comparing the node's key directly to x which tell me that x is not a node but x is the key of node x. If I'm wrong then just remove the key part from elementbyRankTraversal().
And that should work.

Using Instance Variables vs Function Arguments in Recursion

Is there any difference, efficiency-wise, in using instance variables vs passing arguments by function calls during recursion? For example, I was recently doing a problem on Leetcode which asked to:
Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST.
My solution and the most popular one by far is as follows: 46 ms according to Leetcode
class Solution {
public:
int sum = 0;
TreeNode* convertBST(TreeNode* root) {
if (root == NULL) return 0;
convertBST(root->right);
sum += root->val;
root->val = sum;
convertBST(root->left);
return root;
}
};
But why couldn't we also use the following solution, or does it matter? 59 ms runtime according to Leetcode
class Solution {
public:
TreeNode* convertBST(TreeNode* root, int* sum) {
if (root == NULL) return NULL;
convertBST(root->right, sum);
*sum += root->val;
root->val = *sum;
convertBST(root->left, sum);
return root;
}
TreeNode* convertBST(TreeNode* root) {
int sum = 0;
return convertBST(root, & sum);
}
};
Thanks

Computing rank of a node in a binary search tree

If each node in a binary search tree stores its weight (number of nodes in its subtree), what would be an efficient method to compute a rank of a given node (its index in the sorted list) as I search for it in the tree?
Start the rank at zero. As the binary search proceeds down from the root, add the sizes of all the left subtrees that the search skips by, including the left subtree of the found node.
I.e., when the search goes left (from parent to left child), it discovers no new values less than the searched item, so the rank stays the same. When it goes right, the parent plus all the nodes in the left subtree are less than the searched item, so add one plus the left subtree size. When it finds the searched item. any items in the left subtree of the node containing the item are less than it, so add this to the rank.
Putting this all together:
int rank_of(NODE *tree, int val) {
int rank = 0;
while (tree) {
if (val < tree->val) // move to left subtree
tree = tree->left;
else if (val > tree->val) {
rank += 1 + size(tree->left);
tree = tree->right;
}
else
return rank + size(tree->left);
}
return NOT_FOUND; // not found
}
This returns the zero-based rank. If you need 1-based then initialize rank to 1 instead of 0.
Since each node has a field storing its weight, the first you should implement a method call size() which return the number of nodes in a node's substree:
private int size(Node x)
{
if (x == null) return 0;
else return x.N;
}
then compute the rank of a given node is easy
public int rank(Node key)
{ return rank(key,root) }
private int rank(Node key,Node root)
{
if root == null
return 0;
int cmp = key.compareTo(root);
// key are smaller than root, then the rank in the whole tree
// is equal to the rank in the left subtree of the root.
if (cmp < 0) {
return rank(key, root.left)
}
//key are bigger than root,the the rank in the whole tree is equal
// to the size of subtree of the root plus 1 (the root) plus the rank
//in the right sub tree of the root.
else if(cmp > 0){
return size(root.left) + 1 + rank(key,root.right);
}
// key equals to the root, the rank is the size of left subtree of the root
else return size( root.left);
}
Depends on the BST implementation, but I believe you can solve it recursively.
public int rank(Key key){
return rank(root, key);
}
private int rank(Node n, Key key){
int count = 0;
if (n == null)return 0;
if (key.compareTo(n.key) > 0) count++;
return count + rank(n.left, key) + rank(n.right, key);
}

Sum of depth of all nodes in binary tree (Path length)

I am trying to implement a function to calculate path length of a binary tree and i am not able to get the correct answer. Can you check what i am doing wrong? Here is my code below:
public int pathLength() {
int sum = 0;
int c = 1;
pathLength(root, sum);
return sum;
}
public int pathLength(Node n, int sum) {
if(n.isRoot())
sum+= 0;
if(n.left == null && n.right == null)
return;
c++;
if(n.left != null)
sum += c;
if (n.right != null)
sum+=c;
pathLength(n.left, sum);
pathLength(n.right, sum);
}
There are a lot of things wrong with this code. It wouldn't even compile because a) In the 2nd function c is never declared (it is local in the first) and b) the 2nd function never returns a value.
But the biggest issue is the way you declare the 2nd function. "sum" is passed by value. That basically means a new copy of "sum" is created each time you call the function and is discarded when the function ends.
What you want to do is pass by reference. When doing this, the actual sum variable, not a copy, is passed to the function. So your code might look like this:
public void pathLength(Node n, int& sum) {
//if(n.isRoot()) <- not sure what this is for
// sum+= 0;
sum += 1; // Increment for this node
//if(n.left == null && n.right == null)
// return; // This conditional is not needed with next 2 if statements
//c++; <- Don't know what c is for
// Recursively call for child nodes
if(n.left != null)
pathLength(n.left, sum);
if (n.right != null)
pathLength(n.right, sum);
}
Note that this counts all the nodes in the tree. I assume that's what you want. If you want to find the deepest node, that's different.
Is it because of you set the initial value of c as 1 instead of 0?
The children of root should be at level 2 with the depth 1.
Here is an easy approach
Time : O(n) while the space will be O(h) where h is the height of the binary tree:
int sum(BinaryTree *node, int count){
if(node == nullptr){
return 0;
}
return count + sum(node->left, count+1)+sum(node->right, count+1);
}
int nodeDepths(BinaryTree *root) {
int count=0;
int ans=0;
ans =sum(root, count);
return ans;
}

Resources