How much does this algorithm return? Isn't it 1 as left[x] doesn't have children?
NIL = no children
left[x] = left child
right[x] = right child
LEAVES is the name of the algorithm
if (x = nil) then
return 0
else if left[x] = nil then
return 1
else
return Leaves(left[x]) + Leaves(right[x])
end if
I am assuming you want the algorithm to return the number of leaves in the tree. In that case, if a node is equal to NIL then the node is a leaf. Thus the algorithm should be:
def Leaves(x):
if(NotANode(x)):
return 0
if(x==nil):
return 1
return Leaves(left[x]) + Leaves(right[x])
NOTE: I like to use python-like formatting for pseudocode/descriptions of algorithms. Hope you do not mind :) Also note that you did not mention what left[x] is if x is missing only the right child (or vice versa). I assumed that it returned a non-node value and used the made up function NotANode to account for it.
Possible Explanation
Based on how you asked this question I am guessing that this algorithm was given to you and you do not think that it is correct. Is it possible that you do not understand it's purpose?
Normally in programming nil or NULL is used to represent an "empty" object. So the first line if x = nil checks to see if x x is really a node! If it is not then it returns 0 which (assuming the purpose of Leaves is to count the number of leaves in the tree) is correct behavior.
Next we check if the left child of x exists. If it does not then we return 1. The only way this line makes sense is if we can assume that every node fills it's left child first, as then not having a left child means you do not have a right child either and so you are a leaf node (hence the result of 1).
Finally if you do have a left child then the given node is not a leaf and so we must look to it's child subtrees and count their leaves for the answer.
Review the origin of this algorithm to make sure you understand the constraints of the problem and let me know if you need more help :)
Related
Im attempting to write an algorithm that validates a binary search tree. This is to answer the following algorithm question: https://leetcode.com/problems/validate-binary-search-tree/. I've opted to use a recursive approach and have coded the following in Python3:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
left = self.isValidBST(root.left)
right = self.isValidBST(root.right)
if left and right:
if (root.left and root.val <= root.left.val) or (root.right and root.val >= root.right.val):
return False
return True
return False
The algorithm above works up to the 71st test case provided by the leetcode platform. However, it fails on the following input:
[5,4,6,null,null,3,7]
The expected output is False (i.e. not a binary search tree). However, my algorithm outputs True. I've consulted the question description and the diagrams provided multiple times and I believe my output to be correct. With that in mind, is there something I'm missing? Or is the platform incorrect?
The input [5,4,6,null,null,3,7] has the following tree representation.
This is clearly not a valid binary search tree, since the node 3 is less than it's grand parent 5.
In a binary search tree, every node to the right (including all ancestors), must be greater (or grater or equal depending on your definition). The same goes for the left sub trees. Please note that the leetcode problem in this case specifically states that they must be less and greater so equal is not valid. Think about it this way: You need to be able to do a binary search in a BST. When you go right, you expect all the nodes there to be greater than the parent. If a node less than the parent is found there, the ordering is broken and you can't do a binary search. You need to search linearly. Binary searching for 3 in this example would return false, while it's clearly there. So, it isn't a valid binary search tree.
Your algorithm only checks whether the immediate left and right children respect this condition.
To correct it, you need to pass down the min and max allowed values to the recursive function. When you go left, you set the max value equal to the current node value. When you go right you set the min value to the current node value. This makes sure that, say the nodes to the left of a node are never greater than that node.
A possible implementation is as follows:
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
return self.isValidBSTHelper(root, None, None)
def isValidBSTHelper(self, root: TreeNode, min_val: int, max_val: int)-> bool:
if root == None: return True
if (min_val != None and root.val <= min_val) or (max_val != None and root.val >= max_val):
return False
return self.isValidBSTHelper(root.left, min_val, root.val) \
and self.isValidBSTHelper(root.right, root.val, max_val)
I was solving the following job interview question and solved most of it but failed at the last requirement.
Q: Build a data structure which supports the following functions:
Init - Initialise Empty DS. O(1) Time complexity.
SetPositiveInDay(d,x) - Add to the DS that in day d exactly x new people were infected with covid-19. O(log n)Time complexity.
WorseBefore(d) - From the days inserted into the DS and smaller than d return the last one which has more newly infected people than d. O(log n)Time complexity.
For example:
Init()
SetPositiveInDay(1,10)
SetPositiveInDay(2,20)
SetPositiveInDay(3,15)
SetPositiveInDay(5,17)
SetPositiveInDay(23,180)
SetPositiveInDay(8,13)
SetPositiveInDay(13,18)
WorstBefore(13) // Returns day #2
SetPositiveInDay(10,19)
WorstBefore(13) // Returns day #10
Important note: you can't suppose that days will be entered by order and can't suppose too that there won't be "gaps" between days. (Some days may not be saved in the DS while those after it may be).
What I did?
I used AVL tree (I could use 2-3 tree too).
For each node I have:
Sick - Number of new infected people in that day.
maxLeftSick - Max number of infected people for left son.
maxRightSick - Max number of infected people for right son.
When inserted a new node I made sure that in rotation data won't get missed plus, for each single node from the new one till the root I did:
But I wasn't successful implementing WorseBefore(d).
Where to search?
First you need to find the node node corresponding to d in the tree ordered by days. Let x = Sick(node). This can be done in O(log n).
If maxLeftSick(node) > x, the solution must be in the left subtree of node. Search for the solution there and return the answer. This can be done in O(log n) - see below.
Otherwise, traverse the tree upwards towards the root, starting from node, until you find the first node nextPredecessor satisfying this property (this takes O(log n)):
nextPredecessor is smaller than node,
and either
Sick(nextPredecessor) > x or
maxLeftSick(nextPredecessor) > x.
If no such node exists, we give up. In case 1, just return nextPredecessor since that is the best solution.
In case 2, we know that the solution must be in the left subtree of nextPredecessor, so search there and return the answer. Again, this takes O(log n) - see below.
Note that there is no need to search in the right subtree of nextPredecessor since the only nodes that are smaller than node in that subtree would be the left subtree of node itself, and we have already excluded that.
Note also that it is not necessary to traverse further up the tree than nextPredecessor since those nodes are even smaller, and we are looking for the largest node satisfying all constraints.
How to search?
OK, so how do we search for the solution in a subtree? Finding the largest day within a subtree rooted in q that is worse than an infection number x is simple using the maxLeftSick and maxRightSick information:
If q has a right child and maxRightSick(q) > x then search in the right subtree of q.
If q has no right child and Sick(q) > x, return Day(q).
If q has a left child and maxLeftSick(q) > x then search in the left subtree of q.
Otherwise there is no solution within the subtree q.
We are effectively using maxLeftSick and maxRightSick to prune the search tree to include only "worse" nodes, and within that pruned tree we get the right most node, i.e. the one with the largest day.
It is easy to see that this algorithm runs in O(log n) where n is the total number of nodes since the number of steps is bounded by the height of the tree.
Pseudocode
Here is the pseudocode (assuming maxLeftSick and maxRightSick return -1 if no corresponding child node exists):
// Returns the largest day smaller than d such that its
// infection number is larger than the infection number on day d.
// Returns -1 if no such day exists.
int WorstBefore(int d) {
node = find(d);
// try to find the solution in the left subtree
if (maxLeftSick(node) > Sick(node)) {
return FindLastWorseThan(node -> left, Sick(node));
}
// move up towards root until we find the first node
// that is smaller than `node` and such that
// Sick(nextPredecessor) > Sick(node) or
// maxLeftSick(nextPredecessor) > Sick(node).
nextPredecessor = findNextPredecessor(node);
if (nextPredecessor == null) return -1;
// Case 1
if (Sick(nextPredecessor) > Sick(node)) return nextPredecessor;
// Case 2: maxLeftSick(nextPredecessor) > Sick(node)
return FindLastWorseThan(nextPredecessor -> left, Sick(node));
}
// Finds the latest day within the given subtree with root "node" where
// the infection number is larger than x. Runs in O(log(size(q)).
int FindLastWorseThan(Node q, int x) {
if ((q -> right) = null and Sick(q) > x) return Day(q);
if (maxRightSick(q) > x) return FindLastWorseThan(q -> right, x);
if (maxLeftSick(q) > x) return FindLastWorseThan(q -> left, x);
return -1;
}
First of all, your chosen data structure looks fine to me. You did not mention it explicitly, but I assume that the "key" you use in the AVL tree is the day number, i.e. an in-order traversal of the tree would list the nodes in their chronological order.
I would just suggest a cosmetic change: store the maximum value of sick in the node itself, so that you don't have two similar informations (maxLeftSick and maxRightSick) stored in one node instance, but move those two informations to the child nodes, so that your node.maxLeftSick is actually stored in node.left.maxSick, and similarly node.maxRightSick is stored in node.right.maxSick. This is of course not done when that child does not exist, but then we don't need that information either. In your structure maxLeftSick would be 0 when left is not defined. In my proposed structure, you would not have that value -- the 0 would follow naturally from the fact that there is no left child. In my proposal, the root node would have an information in maxSick which is not present in yours, and which would be the sum of your root.maxLeftSick and root.maxRightSick. This information would not really be used, but it is just there to make the structure consistent throughout the tree.
So you would just store one maxSick, which considers the current node's sick value also in that maximum. The processing you do during rotations will need to change accordingly, but will not become more complex.
I will assume that your AVL tree is single-threaded, i.e. you don't keep track of parent-pointers. So create a find method which will return the path to the node to be found. For instance, in Python syntax, it could look like this:
def find(self, day):
node = self.root
path = [] # an array of nodes
while node:
path.append(node)
if node.day == day: # bingo
return path
if day < node.day:
node = node.left
else:
node = node.right
Then the worstBefore method could look like this:
def worstBefore(self, day):
path = self.find(day)
if not path:
return # day not found
# get number of sick people on that day:
sick = path[-1].sick
# look for recent day with greater number of sick
while path:
node = path.pop() # walk upward, starting with found node
if node.day < day and node.sick > sick:
return node.day
if node.left and node.left.maxSick > sick:
# we will find the result in this subtree
node = node.left
while True:
if node.right and node.right.maxSick > sick:
node = node.right
elif node.sick > sick: # bingo
return node.day
else:
node = node.left
So the path returned by the find method will be used to get the parents of a node when you need to backtrack upwards in the tree along that path.
If along that path you find a left child whose maxSick is greater, then you know that the targeted node must be in that subtree. It is then a matter to walk down that subtree in a controlled way, choosing the right child when it still has maxSick greater. Otherwise check the current node's sick value and return that one if that value is greater. Otherwise go left, and repeat.
While there is no such left sub tree, go up along the path. If that parent would be a match, then return it (make sure to verify the day number). Keep checking for left sub trees that have a larger maxSick.
This runs in O(logn) because you first will walk zero or more steps upward and then zero or more steps downward (in a left subtree).
You can see your example scenario run on repl.it. There I focussed on this question, and didn't implement the rotations.
I've read a lot of documents regarding minimax algorithm and it's implementation on the game of tic-tac-toe but I'm really having a hard time applying it.
Here are links that I've read 1, 2, 3, 4, 5 and an example using java 6
Considering the pseudocode: 7
function minimax(node, depth, maximizingPlayer)
if depth = 0 or node is a terminal node
return the heuristic value of node
if (maximizingPlayer is TRUE) {
bestValue = +∞
for each child of the node {
val = minimax(child, depth-1, FALSE)
bestValue = max(bestValue, val)
}
return bestValue
} else if maximizingPlayer is FALSE {
bestValue = -∞
for each child of the node {
val = minimax(child, depth-1, TRUE)
bestValue = min(bestValue, val)
}
return bestValue
}
Here are my questions:
1. What will I pass to the signature node, is it the valid moves for the current player?
2. What is + and - infinity, What are their possible values?
3. What is the relationship between minimax and the occupied cells on the board.
4. What are child nodes how are values extracted from it?
5. How will I determine the maximum allowed depth?
Node is the grid with the information of which cells were already played
±∞ is just a placeholder, you can take int.maxValue or any other "big"/"small" value in your programming language. It is used later as a comparison to the calculated value of a node and 0 might already be a valid value. (Your pseudocode is wrong there, if we assign +∞ to bestValue, we want min(bestValue, val) and max(bestValue, val) for -∞.
Not sure what you mean.
Child nodes are possible moves that can be made. Once no move can be made the board is evaluated and score is returned.
The search space in TicTacToe is very small, in other games a heuristic score is returned, depending if the situation is is favorable to the player or not. In your scenario there should be no hard depth.
First of all, stop asking 100 questions in one question. Ask one, try to understand and figure out whether you actually need to ask another.
Now to your questions:
What will I pass to the signature node, is it the valid moves for the
current player?
No, you will pass only node, depth, maximizingPlayer (who plays - min or max). Here for each child of the node you find the possible moves from that node. In real scenario most probably you will have a generator like getChildren using which you will get your children
What is + and - infinity, What are their possible values?
minimax algorithm just tries to find the maximum value over all minimum values recursively. What is the worst possible result a maximum player can get - -infinity. The worse for minimum is when maximum will get +infinity. So these are just starting values.
What is the relationship between minimax and the occupied cells on the
board.
Not sure what do you mean here. Minimax is the algorithm, occupied cell is an occupied cell. This question is similar to what is the relation between dynamic programming and csv file.
What are child nodes how are values extracted from it?
they are all possible positions that can be reached from your current position. For example
How will I determine the maximum allowed depth?
In standard minimax it is till you will reach the end of the tree. At the end of the tree your evaluation function will give you a reward. Because the tree is most of the time too huge to fit anywhere people use a cutoff and use approximation to evaluation function (heuristics). The easiest cut of is look n moves ahead and hope that your evaluation function is good enough and your opponent think n-1 moves ahead.
I have been given this problem to solve:
Suppose you're given a doubly-linked list and a pointer to some element of that list. Let's suppose that you want to search the list for some value v, which you know exists somewhere. Using no pointers except p, design an Θ(m)-time algorithm for finding v, where m is the distance between p and the node containing v. Do not modify the input list.
Does anyone have any ideas how to solve this? The only way I can think of doing this destructively modifies the list.
As a hint: What happens if you take one step forward, two steps back, four steps forward, eight steps back, etc.? How many total steps will it take to find the element?
When doing the analysis, you might find it useful to sum up a geometric series. If it helps, 1 + r + r2 + r3 + ... + rn-1 = (rn - 1) / (r - 1).
Hope this helps!
I think templatetypedef has the correct answer, but the below solution came to mind, based on the original phrasing of the question, which states that the list can't be "destroyed or shuffled", which might imply that modifying it is okay if you can change it back again - even if this is not true, I still think this is an interesting approach.
It can easily be solved with 2 pointers, right? One to go forward and one to go back, moving both at the same time until you the value you're looking for.
Now this is all well and good, except that we're only allowed to have 1 pointer.
If you think about a double linked-list, we know that the previous node's next pointer is just a pointer to the current element, so, if we were to lose it, we could just set it up again.
So we could use p.prev.next as free storage (and p.prev.prev.next, given a similar argument).
So, we could only use one pointer going forward, and store the one going back in p.prev.next, moving it appropriately as we go along.
Some Java-esque pseudo-code ignoring end-of-list checks and not finding it for simplicity (I think it's already complicated enough):
if p.data == v
return v
p = p.next
p.prev.next = p.prev.prev
while not found
if p == v || p.prev.next == v
p.prev.next = p // restore p.prev.next
return v
p = p.next
p.prev.next = p.prev.prev.next.prev // set up p.prev.next from p.prev.prev.next
p.prev.prev.next = p.prev // restore p.prev.prev.next
struct node {
int value;
struct node* left;
struct node* right;
int left_sum;
int right_sum;
}
In a binary tree, from a particular node, there is a simply recursive algorithm to sum up all its child values. Is there a way to save the values calculated in the intermediate steps and store them as left_sum and right_sum in child nodes?
Will it be easier to do this bottom up by adding a struct node* parent link to the node definition?
No, this is clearly an exercise in recursion. Think about what the sum means. It's zero plus the "sum of all values from the root down".
Interestingly enough, the "sum of all values from the root down" is the value of the root node plus the "sum of all values from its left node down" plus the "sum of all values from its right node down".
Hopefully, you can see where I'm going here.
The essence of recursion is to define an operation in terms of similar, simpler, operations with a terminating condition.
The terminating condition, in this case, is the leaf nodes of the tree or, to make the code simpler, beyond the leaf nodes.
Examine the following pseudo-code:
def sumAllNodes (node):
if node == NULL:
return 0
return node.value + sumAllNodes (node.left) + sumAllNodes (node.right)
fullSum = sumAllNodes (rootnode)
That's really all there is to it. With the following tree:
__A(9)__
/ \
B(3) C(2)
/ \ \
D(21) E(7) F(1)
Using the pseudo-code, the sum is the value of A (9) plus the sums of the left and right subtrees.
The left subtree of A is the value of B (3) plus the sums of its left and right subtrees.
The left subtree of B is the value of D (21) plus the sums of its left and right subtrees.
The left subtree of D is the value of NULL (0).
Later on, the right subtree of A is the value of C (2) plus the sums of its left and right subtrees, it's left subtree being empty, its right subtree being F (1).
Because you're doing this recursively, you don't explicitly ever walk your way up the tree. It's the fact that the recursive calls are returning with the summed values which gives that ability. In other words, it happens under the covers.
And the other part of your question is not really useful though, of course, there may be unstated requirements that I'm not taking into account, because they're, well, ... unstated :-)
Is there a way to save the values calculated in the intermediate steps and store them as left_sum and right_sum in child nodes?
You never actually re-use the sums for a given sub-tree. During a sum calculation, you would calculate the B-and-below subtree only once as part of adding it to A and the C-and-below subtree.
You could store those values so that B contained both the value and the two sums (left and right) - this would mean that every change to the tree would have to propagate itself up to the root as well but it's doable.
Now there are some situations where that may be useful. For example, if the tree itself changes very rarely but you want the sum very frequently, it makes sense performance wise to do it on update so that the cost is amortised across lots of reads.
I sometimes use this method with databases (which are mostly read far more often than written) but it's unusual to see it in "normal" binary trees.
Another possible optimisation: just maintain the sum as a separate variable in the tree object. Initialise it to zero then, whenever you add a node, add its value to the sum.
When you delete a node, subtract its value from the sum. That gives you your very fast O(1) "return sum" function without having to propagate upwards on update.
The downside is that you only have a sum for the tree as a whole but I'm having a hard time coming up with a valid use case for needing the sum of subtrees. If you have such a use case, then I'd go for something like:
def updateAllNodes (node):
if node == NULL:
return 0
node.leftSum = updateAllNodes (node.left)
node.rightSum = updateAllNodes (node.right)
return node.value + node.leftSum + node.rightSum
change the tree somehow (possibly many times)
fullSum = updateAllNodes (root)
In other words, just update the entire tree after each change (or batch the changes then update if you know there's quite a few changes happening). This will probably be a little simpler than trying to do it as part of the tree update itself.
You can even use a separate dirtyFlag which is set to true whenever the tree changes and set to false whenever you calculate and store the sum. Then use that in the sum calculation code to only do the recalc if it's dirty (in other words, a cache of the sums).
That way, code like:
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
will only incur a cost on the first invocation. The other four should be blindingly fast since the sum is cached.