ClosestKeyBefore(k) in a BST - binary-search-tree

I am trying to find the closest key to k before k is reached in a binary search tree.
The more I think about it, the more I get confused as to where it could possibly be.
Formal definition of this method:
Return the key of the item with the largest key less than or equal to k
At first I thought it would be the parent of k.. but after looking at BSTs its becoming very unclear to me. I need the algorithm for this.
It should run in O(h) time where h is the height of the tree.
Thanks!

I guess you could make use of recursion to remember your current best value (ie. closest so far). If value is bigger than the current node, you search the right subtree and you know your current node is the best answer IF there is nothing found in right subtree. In the search of the right subtree, you return your current best answer (less than or equal) and this answer will just propagate up.
When value is less than current node, you search the left subtree. The current node cannot be your best answer because it is greater than the value you're searching. Hence just return whatever left subtree returns.
The code would look something like this. This is just a simple example with integers and it returns -1 when no valid values are found.
public static int closestKeyBefore(Node node, int val) {
if(node==null) return -1;
if(node.value == val) return val;
int retval = -1;
if(node.value<val) { // Value is bigger than current node, search right
retval = closestKeyBefore(node.right,val);
if(retval==-1) { //Not found in right subtree
retval = node.value; // Current node is the best answer. return this
}
}
else { // Value is smaller than current node, search left
retval = closestKeyBefore(node.left,val);
}
return retval;
}

Related

Time complecity big O of modifided DFS (using DFS to search for path in maze)

I wrote a program that solves maze that is not ideal (has 1 or more correct paths) using recursion DFS algorithm. I have a problem with the time complexity of my program, becouse i read on the internet that the time complexity for DFS is O(v+n) where n is the number of node and v the number of edges. In my case if i don't find the correct path i go back and go the other bath if there is a branching, so i am thinking how it will affect my time complexity. NOTE(mazes that i use are directed graph, so i can't go back and have to go from up to down)
void DFS3 (int *visited, double **graf, int *paths, int **results, int n, int v, int end){
visited [ v ] = 1;
if(v==end){ // if we find the end we write the table of paths (our path) to the table of results
results[r][0]=k+1;
for(int j=1;j<k+1;j++)
results[r][j]=paths[j-1];
results[r][k+1]=end; // we write the last node (our wayout) to the table of results (it's not included in table of path)
r++;
visited[v]=0; // we mark the last node as not visited
}
for(int i = 1; i < n*n+1; i++ ){
if( ( graf [ v ][ i ] != 0 ) && visited [ i ] != 1 ){
paths[k]=v; // if we find the connection between node (a path) we write it to the paths and run the DFS3 of this node
k++;
DFS3 ( visited, graf, paths,results, n, i, end);
}
}
paths[k]=0; // if there is a dead end we go back to the first branching and delete the nodes that aren't correct path
k--;
visited[v]=0; // we mark them as unvisited
}
In DFS, as long as you are marking the nodes as already visited, you can avoid visiting them again. So, while you still have to evaluate all the edges (and there can be O(|V|^2 many directed edges), you don't have to go back down old paths.
If you want the shortest path through the maze (and not just the first one you happen to find), DFS is not great since you'd need to let it keep running to find all paths, then choose the shortest one. BFS will get you the shortest path first, but almost surely take longer to find a path through than DFS would. But, it's also O(|V| + |E|)

Efficient way of Square of a Sorted Array

I am solving leetcode solution. The question is
Given an integer array nums sorted in non-decreasing order, return an array of the squares of each number sorted in non-decreasing order.
Example 1:
Input: nums = [-4,-1,0,3,10]
Output: [0,1,9,16,100]
Explanation: After squaring, the array becomes [16,1,0,9,100].
After sorting, it becomes [0,1,9,16,100].
Example 2:
Input: nums = [-7,-3,2,3,11]
Output: [4,9,9,49,121]
I solved this through map and then use sorted() for sorting purpose and lastly converted in toIntArray().
My solution
class Solution {
fun sortedSquares(nums: IntArray): IntArray {
return nums.map { it * it }.sorted().toIntArray()
}
}
After all I am taking a look in the discuss success, I found this solution
class Solution {
fun sortedSquares(A: IntArray): IntArray {
// Create markers to use to navigate inward since we know that
// the polar ends are (possibly, but not always) the largest
var leftMarker = 0
var rightMarker = A.size - 1
// Create a marker to track insertions into the new array
var resultIndex = A.size - 1
val result = IntArray(A.size)
// Iterate over the items until the markers reach each other.
// Its likely a little faster to consider the case where the left
// marker is no longer producing elements that are less than zero.
while (leftMarker <= rightMarker) {
// Grab the absolute values of the elements at the respective
// markers so they can be compared and inserted into the right
// index.
val left = Math.abs(A[leftMarker])
val right = Math.abs(A[rightMarker])
// Do checks to decide which item to insert next.
result[resultIndex] = if (right > left) {
rightMarker--
right * right
} else {
leftMarker++
left * left
}
// Once the item is inserted we can update the index we want
// to insert at next.
resultIndex--
}
return result
}
}
The guy also mention in the title Kotlin -- O(n), 95% time, 100% space
So my solution is equal in time and space complexity with other solution with efficient time and space? Or Is there any better solution?
So my solution is equal in time and space complexity with other solution with efficient time and space?
No, your solution runs in O(n log n) time, as it relies on sorted(), which likely runs in O(n log n). Since the alternative solution does not sort the items, it indeed runs on O(n) time. Both solutions use O(n) space, although your solution uses three times as much space (each of map, sorted and toIntArray create a copy of the input).

What is the time complexity of below function?

I was reading book about competitive programming and was encountered to problem where we have to count all possible paths in the n*n matrix.
Now the conditions are :
`
1. All cells must be visited for once (cells must not be unvisited or visited more than once)
2. Path should start from (1,1) and end at (n,n)
3. Possible moves are right, left, up, down from current cell
4. You cannot go out of the grid
Now this my code for the problem :
typedef long long ll;
ll path_count(ll n,vector<vector<bool>>& done,ll r,ll c){
ll count=0;
done[r][c] = true;
if(r==(n-1) && c==(n-1)){
for(ll i=0;i<n;i++){
for(ll j=0;j<n;j++) if(!done[i][j]) {
done[r][c]=false;
return 0;
}
}
count++;
}
else {
if((r+1)<n && !done[r+1][c]) count+=path_count(n,done,r+1,c);
if((r-1)>=0 && !done[r-1][c]) count+=path_count(n,done,r-1,c);
if((c+1)<n && !done[r][c+1]) count+=path_count(n,done,r,c+1);
if((c-1)>=0 && !done[r][c-1]) count+=path_count(n,done,r,c-1);
}
done[r][c] = false;
return count;
}
Here if we define recurrence relation then it can be like: T(n) = 4T(n-1)+n2
Is this recurrence relation true? I don't think so because if we use masters theorem then it would give us result as O(4n*n2) and I don't think it can be of this order.
The reason, why I am telling, is this because when I use it for 7*7 matrix it takes around 110.09 seconds and I don't think for n=7 O(4n*n2) should take that much time.
If we calculate it for n=7 the approx instructions can be 47*77 = 802816 ~ 106. For such amount of instruction it should not take that much time. So here I conclude that my recurrene relation is false.
This code generates output as 111712 for 7 and it is same as the book's output. So code is right.
So what is the correct time complexity??
No, the complexity is not O(4^n * n^2).
Consider the 4^n in your notation. This means, going to a depth of at most n - or 7 in your case, and having 4 choices at each level. But this is not the case. In the 8th, level you still have multiple choices where to go next. In fact, you are branching until you find the path, which is of depth n^2.
So, a non tight bound will give us O(4^(n^2) * n^2). This bound however is far from being tight, as it assumes you have 4 valid choices from each of your recursive calls. This is not the case.
I am not sure how much tighter it can be, but a first attempt will drop it to O(3^(n^2) * n^2), since you cannot go from the node you came from. This bound is still far from optimal.

find Kth element in a Binary Search tree

I'm learning about Binary Search Trees. I want to return the k-th element of the in-order traversal of the binary search tree. How can I keep the variable 'count' updated or is there some way to break out of the loop once I find the k-th element and print it out?
public void kthElement(int n, int count, BinaryNode<AnyType> root){
if( root.left !=null)
this.kthElement(n, count, root.left);
count++;
if(count==n){
System.out.println(root.element);
}
else if(count!=n){
return;}
if( root.right != null)
this.kthElement(n, count, root.right);
}
I can think of two solutions.
Declare a field for each node stating how many elements are in it's right subtree and left subtree, from here it should be easy to proceed.
If you're allowed to use additional memory, copy the elements to a dynamically allocated sorted array (using inorder traversal) and return the k'th element.

find the smallest depth leaf node in bst

Need to get the leaf node that has minimum depth. I cannot think of a good way to do it without storing additional information in each node, please suggest, thanks very much.
The brute force solution is a breadth-first search terminating at the first leaf found, this will be easier to implement iteratively than recursively.
See for instance the pseudo-code in my answer to "Breadth First Vs Depth First" just add another condition to the while-loop.
BTW--This will get you a leaf with the minimum depth, as there may be more than one at that depth. Getting the full set of minimum depth leaves is a little harder. I guess go with an iterative deepening strategy.
Finding out what level that node is one.
Three choices:
Find the node first and the search down the tree for it. It sounds wasteful, but that second search requires visiting only as many nodes as the level, so it really is fast.
Alternately you can keep track as you go. You use three counters levelCounter, thisLevelCounter and nextLevelCounter. Every time you more to a new node you decrement thisLevelCounter, and when it hits zero you've moved down a level so do
levelCounter++
thisLevelCounter = nextLevelCounter
nextLevelCounter = 0
Every time you add a child node to the search list, increment nextLevelCounter.
Every time you store a new child node increment nextLevelCounter
Finally, the iterative deepening strategy gives you the sucess level for free (which iteration finds it...) and has the same order of performance (though a slightly higher multiplier) as the breadth first search.
Here code version (hope I didn't miss any error check):
void min_leaf(node_t *t, int *min, int lev, node_t **n) {
if (!t) {
return;
}
if (lev > *min) {
printf("Back from %d at lev %d, min: %d already found\n",
t->key,
lev,
*min);
return;
}
if (!t->left && !t->right) {
if (*min > lev) {
*min = lev;
*n = t;
}
} else {
min_leaf(t->left, min, lev+1, n);
min_leaf(t->right, min, lev+1, n);
}
}
void bst_print_min_leaf(bst_t* bst) {
int min = 10000; /* Replace it with some really large number */
node_t *minn = NULL;
min_leaf(bst->root, &min, 0, &minn); /*level: root is level 0 */
if (minn) printf("min leaf is at depth: %d: (%p:%d)\n", min, minn, minn->key);
}