The problem I am tackle with is to find the first occurrence node in its inorder traversal in a BST.
The code I have is given below
def Inorder_search_recursive(node,key):
if not node:
return None
InOrder_search_recursive(node.lChild)
if node.value==key:
return node
InOrder_search_recursive(node.rChild)
This code always return None, what's wrong with it. I think I've return node when I find a node with value k. Why cannot python pass this node???Thanks in advance
When you call yourself recursively, like this:
InOrder_search_recursive(node.lChild)
That's just a normal function call, like any other. It just calls the function and gets back a result. It doesn't automatically return the value from that function, or do anything else.
So, you do the left-subtree search, ignore the results, then go on to check node.value == key, and, if that fails, you do the right-subtree search, again ignore the results, and fall off the end of the function, meaning you return None.
To make this work, you need to return the value you got back. But, of course, only if it's not None.
Also, you forgot to pass the key argument down to the recursive call, so you're just going to get a TypeError. (I'm guessing your real code doesn't have this problem, but since you didn't show us your real code, or a working example, I can't be sure…)
So:
def Inorder_search_recursive(node, key):
if not node:
return None
result = InOrder_search_recursive(node.lChild, key)
if result is not None:
return result
if node.value==key:
return node
return InOrder_search_recursive(node.rChild, key)
(You don't need the not None check for the right-side search, because if it returns None, we have nothing else to try and are just going to return None anyway.)
My other answer gives the novice-friendly solution, but if you want more powerful and concise answer:
def Inorder_search_recursive_all(node, key):
if not node:
return
yield from InOrder_search_recursive(node.lChild, key)
if node.value==key:
yield node
yield from InOrder_search_recursive(node.rChild, key)
This generates all matches in the tree, in order. And it gives them to you as an iterator, so if you just want the first, you can stop as soon as you find one, with no wasted work:
def Inorder_search_recursive(node, key):
return next(Inorder_search_recursive_all(node, key), None)
The tutorial section on Iterators and the following section on Generators explains most of how this works. The only missing bit is an explanation of yield from, which is explained in PEP 380.
Since your problem is to find the first occurrence node in its inorder traversal, you should 1) traverse the tree in-order and 2) stop when you find the first occurrence.
def search(node, key):
if node is None:
return None
# Search the left subtree and return early if key is found
n = search(node.lChild, key)
if n is not None:
return n
# Check middle and return early if key is found
if node.value == key:
return node
# Search right subtree
return search(node.rChild, key)
Related
Returning list inside of list (not desired)
I keep returning a list inside of a list for the following LeetCode Problem 257. Binary Tree Paths, which is not what the problem wants. I always seem to run into this issue while solving traversal problems.
Here is my current solution along with it's output.
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def binaryTreePaths(self, root: TreeNode, val: str="") -> List[str]:
if not root:
return ""
val += str(root.val) + "->"
if not root.left and not root.right:
return val[:-2]
return [path for path in [self.binaryTreePaths(root.left, val), self.binaryTreePaths(root.right, val)] if path]
Input: [1,2,3,null,5]
Output: [["1->2->5"],"1->3"]
Expected: ["1->2->5","1->3"]
Things I've tried
Creating a res variable and using res.extend()
res = []
res.extend(path for path in [self.binaryTreePaths(root.left, val), self.binaryTreePaths(root.right, val)] if path)
Using append instead of extend along with conditionals to try and filter out unwanted elements.
I constantly run into this problem while solving traversal problems so if anyone here has a solution along with some general advice on how to develop an intuition on what's going wrong here and how to solve it in the future, I'd be extremely grateful for your help.
Edit
Well I kept working at trying to fix my solution and after about ~20 minutes, I came up with the following abomination.
class Solution:
def binaryTreePaths(self, root: TreeNode, val: str="") -> List[str]:
if not root:
return ""
val += str(root.val) + "->"
if not root.left and not root.right:
return val[:-2]
r1 = self.binaryTreePaths(root.left, val)
r2 = self.binaryTreePaths(root.right, val)
if isinstance(r1, str):
r1 = [r1]
if isinstance(r2, str):
r2 = [r2]
for i in r1:
if i == "":
r1.pop(r1.index(i))
for i in r2:
if i == "":
r2.pop(r2.index(i))
return r1 + r2
I'm by no means satisfied with my solution as is so if you know of a cleaner fix please continue to post your fix/advice.
The root issue is that the binaryTreePaths function returns different types depending on the conditions. If root is falsy or when there is no left or right set, it returns just a string ("" or val[:-2]), but in all other cases it returns a list.
The list is only needed for the first level of regression (when returning the final value back to the caller), but the way it is setup it can also return a list from any level of recursion. So, any recursion that also meets the criteria to return the list comprehension will end up with a list within a list at the lower levels of recursion.
So, when you travel more than one node, it will be encased in a list for each additional node. Thus, "1->3" isn't in a list because it was immediately returned as a string after the first recursion on the right side, but "1->2->5" was in a list because there was one extra level of recursion before the string was returned.
There are multiple ways to resolve this - you could track the level of regression and only respond with left/right strings at any depth above 1, then return the list only from level 1, for example. Or you could have a parent function that handles the first layer and a helper function (perhaps a child function within it) that does the recursion part.
Half the fun is figuring it out - so I leave the code piece to you. Hopefully this gave you to tools to resolve it yourself (per the second half of your question). The key is to construct at each recursion level exactly what the return value is. The best way to do this in real-time is to run your code in debugging mode, putting a breakpoint at the start of the recursive function, and follow the code through, and look at what the actual arguments and return values are as it recurses. Do this a few times and you will start to be able to think your way through what is happening without the debugging.
(edit: another trick you can use is writing out the list comprehension long-form - with for loops and if/else statements. It's not as compact, but usually makes it easier to understand which values get assigned when.)
For this problem, we can use stack. This'd get accepted:
class Solution:
def binaryTreePaths(self, root):
if not root:
return []
paths = []
stack = [(root, '')]
while stack:
node, path = stack.pop()
if not node.left and not node.right:
paths.append(f'{path}{node.val}')
if node.right:
stack.append((node.right, f'{path}{node.val}->'))
if node.left:
stack.append((node.left, f'{path}{node.val}->'))
return paths
Here is also LeetCode's recursive solution:
class Solution:
def binaryTreePaths(self, root):
"""
:type root: TreeNode
:rtype: List[str]
"""
def construct_paths(root, path):
if root:
path += str(root.val)
if not root.left and not root.right: # if reach a leaf
paths.append(path) # update paths
else:
path += '->' # extend the current path
construct_paths(root.left, path)
construct_paths(root.right, path)
paths = []
construct_paths(root, '')
return paths
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
Question link is here
The recursion method need to traverse the tree twice.
But one of the comment provided a solution used a technique called 'Null check'. I can't understand why in this way can we avoid checking the tree twice?
Here is his code in C++:
bool isSymmetric(TreeNode* root) {
if (!root) return true;
return isSymmetric(root->left, root->right);
}
bool isSymmetric(TreeNode* t1, TreeNode* t2){
if (!t1 && !t2) return true;
if (!t1 || !t2) return false;
return t1->val == t2->val
&& isSymmetric(t1->left, t2->right)
&& isSymmetric(t1->right, t2->left);
}
I have also tried to modify it into python3 and my code also passed all test cases!
Here is my code:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root):
return self.helper(root)
def helper(self,root):
if root is None:
return True
#why we can redefine the helper here?
def helper(left,right):
if left is None and right is None:
return True
if left is None or right is None:
return False
return left.val==right.val and helper(left.left,right.right) and helper(left.right,right.left)
return helper(root.left,root.right)
I have never met such kind of recursion before.
(1) Why we can redefine the function helper with different arguments in helper function itself?
(2) My intuition tells me that helper function will stop execution once it returns back to the root thus the tree won't be checked twice. But I don't know why.
A def statement is really just a fancy assignment statement. In Solution.helper, you are defining a local variable named helper that is bound to another function. As a result, all references inside Solution.helper and the local function to the name helper resolve to the local function.
Solution.helper is not a recursive function; only the local function is. You could write the same thing (less confusingly but equivalently) as
class Solution:
def isSymmetric(self, root):
return self.helper(root)
def helper(self,root):
if root is None:
return True
def helper2(left,right):
if left is None and right is None:
return True
if left is None or right is None:
return False
return left.val==right.val and helper2(left.left,right.right) and helper2(left.right,right.left)
return helper2(root.left,root.right)
The role of function isSymmetric(TreeNode* root is pretty simple. First, it returns true if the tree is empty, and if it's not, it checks if its left child is a mirror of its right child, which happens in the isSymmetric(TreeNode* t1, TreeNode* t2). So let's try to understand how the second function works. It is essentially designed to take two trees and check if they are mirrors of each other. How? First, it does the obvious checks. If one is null and the other is not, it returns false, and if both are null it returns true. The interesting part happens when both are potentially trees. It suffices that the left child of one is the mirror of the right child of the other and vice versa. You can draw a tree to see why this is the case. A schema should be self-explanatory.
I need to implement a Binary Search Tree class as homework but I struggle making the insert function. I have looked through Google a lot to find some solutions or possibilities on how to do it but none of them has used a key and value (mostly just value) or if they used a key aswell, they had tons of seperate functions which I am not allowed to do I think.
So the pre-built is simply that:
class Node:
def __init__(self, key, value):
self.key = key
self.value = value
self.left = self.right = None
class BinarySearchTree:
def __init__(self):
self.root = None
self.size = 0
def __len__(self):
return self.size
def insert(self, key, value):
pass
def remove(self, key):
pass
def find(self, key):
pass
Now the thing is, if I want to check for example whether the value is smaller or bigger than a current Node to put it either right or left, I get Errors such as "root is not defined" or "root.right" has no such attribute etc...
And I guess that makes sense because self.root is declared as None.
But how do I actually fix it now to make the insert function work?
I am a little confused by this task as it uses key + value, so I need to insert the value bound to the specific key and in case the key already existed, overwrite its value.
its 5 in the morning so this might be all wrong, but here goes:
the key is what we are sorting by, the values aren't interesting
your insert function should probably look something like this:
def insert(self, key, value):
if self.root = None:
self.root = Node(key,value)
return
#regular binary tree traversal (comparing the key) to find where to insert, lets assume we need to insert on the left
parent.left = Node(key,value)
can you figure it out from here or would you like more direction
You didn't specify, but I'm guessing the point of the keys is to determine if a particular key is already in the tree, and if so, replace the related node's value in O(1) runtime complexity.
So when you're inserting a node, you will first check the dictionary for the key (you will initialize an empty dictionary yourself in __init__). If it already is there, then you simply just need to replace the value of the node for that particular key. Otherwise, you add the new node the same way that you would in any BST, and also remember to update your dictionary to map the key to it's node.
I am a novice who has just finished edX's introductory course MIT 6.00.1x; the following is related to a problem on that course's final exam (now concluded, so I can seek help). Let
def class DLLNode(object):
def __init__(self, name):
self.cargo = cargo
self.before = None
self.after = None
def setBefore(self, before): self.before = before
def setAfter(self, after): self.after = after
def getBefore(self): return self.before
def getAfter(self): return self.after
def getCargo(self): return self.cargo
be used to create a doubly linked list. Suppose node is an instance of class DLLNode that appears in a doubly linked list. Then node.getBefore() returns that node's immediate predecessor in the list, except that it returns None if node is at the front of the list and so has no predecessor.
I have written a recursive function
def firstInList(nodeInList):
""" Prints out the cargo carried by the first node in that doubly linked list
of which nodeInList is a part. Returns that first node. """
if nodeInList.getBefore() == None:
firstnode = nodeInList
print firstnode.getCargo()
return firstnode
# nodeInList.getBefore() is not None, so nodeInList has an immediate predecessor
# on which firstInList can be be called.
firstInList(nodeInList.getBefore())
that I wish to return the first node in a doubly linked list, given as argument a known node nodeInList in the list.
My problem: firstInList arrives at the correct first node, as evidenced by its printing the first node's cargo regardless of the specific nodeInList used. But whenever nodeInList is not the first node in the linked list, the return value of firstInList(node) turns out to be None rather than the desired first node. This conclusion is based on the following: If, for example, the list's first node node1 has cargo 1 and is followed by node2 with cargo 2, then firstInList(node2) == None evaluates as True but firstInList(node2) == node1 evaluates as False. A call firstInList(node2).getCargo() will return an error message
Attribute Error: 'NoneType' object has no attribute 'getCargo'
Another datum is that firstInList(node1) == node1 evaluates as True; that, at least, is as I would expect.
This suggests the firstnode found is not being returned back up the chain of recursive calls in the way I have imagined. Can anyone explain why?
(Please do not suggest that I use iteration instead of recursion. I know how to do that. I am trying to understand Python 2.7's behavior for the code as written.)
Well, it would appear that you're not returning the result of the recursion, so the function will in all cases but the degenerate simply return the default uninitialized value.
The last line should be:
return firstInList(nodeInList.getBefore())
Many thanks to Nathan Tuggy. At first I misunderstood what you were saying, but in fact you were correct.
My firstInList function worked perfectly once I changed the last line
firstInList(nodeInList.getBefore())
to read
return firstInList(nodeInList.getBefore()) .
Given the ridiculous number of hours I've spent worrying about this, I think this is a type of mistake I'm not likely to make in the future. Or if I do, I'll be able to discover the problem myself.
I'm trying to solve this newbie puzzle:
I've created this function:
def bucket_loop(htable, key):
bucket = hashtable_get_bucket(htable, key)
for entry in bucket:
if entry[0] == key:
return entry[1]
return None
And I have to call it in two other functions (bellow) in the following way: to change the value of the element entry[1] or to append to this list (entry) a new element. But I can't do that calling the function bucket_loop the way I did because "you can't assign to function call" (assigning to a function call is illegal in Python). What is the alternative (most similar to the code I wrote) to do this (bucket_loop(htable, key) = value and hashtable_get_bucket(htable, key).append([key, value]))?
def hashtable_update(htable, key, value):
if bucket_loop(htable, key) != None:
bucket_loop(htable, key) = value
else:
hashtable_get_bucket(htable, key).append([key, value])
def hashtable_lookup(htable, key):
return bucket_loop(htable, key)
Thanks, in advance, for any help!
This is the rest of the code to make this script works:
def make_hashtable(size):
table = []
for unused in range(0, size):
table.append([])
return table
def hash_string(s, size):
h = 0
for c in s:
h = h + ord(c)
return h % size
def hashtable_get_bucket(htable, key):
return htable[hash_string(key, len(htable))]
Similar question (but didn't help me): SyntaxError: "can't assign to function call"
In general, there are three things you can do:
Write “setter” functions (ex, bucket_set)
Return mutable values (ex, bucket_get(table, key).append(42) if the value is a list)
Use a class which overrides __getitem__ and __setitem__
For example, you could have a class like like:
class Bucket(object):
def __setitem__(self, key, value):
# … implementation …
def __getitem__(self, key):
# … implementation …
return value
Then use it like this:
>>> b = Bucket()
>>> b["foo"] = 42
>>> b["foo"]
42
>>>
This would be the most Pythonic way to do it.
One option that would require few changes would be adding a third argument to bucket_loop, optional, to use for assignment:
empty = object() # An object that's guaranteed not to be in your htable
def bucket_loop(htable, key, value=empty):
bucket = hashtable_get_bucket(htable, key)
for entry in bucket:
if entry[0] == key:
if value is not empty: # Reference (id) comparison
entry[1] = value
return entry[1]
else: # I think this else is unnecessary/buggy
return None
However, a few pointers:
I agree with Ignacio Vazquez-Abrams and David Wolever, a class would be better;
Since a bucket can have more than one key/value pairs, you shouldn't return None if the first entry didn't match your key. Loop through all of them, and only return None in the end; (you can ommit this statement also, the default behavior is to return None)
If your htable doesn't admit None as a value, you can use it instead of empty.
So you're basically cheating at udacity, which is an online cs class / university? Funny part is you couldn't even declare the question properly. Next time cheat thoroughly and paste the two functions you're supposed to simplify and request someone simplify them by creating a third function with the overlapping code within. Doesn't matter anyway because if this is the one you need help in you're likely not doing very well in the class
you were also able to solve the problem without using most of these tools, it was an exercise in understanding how to identify an handle redundancies, NOT efficiency...
Real instructions:
Modify the code for both hashtable_update and hashtable_lookup to have the same behavior they have now, but using fewer lines of code in each procedure. You should define a new procedure, helper, to help with this. Your new version should have approximately the same running time as the original version, but neither
hashtable_update or hashtable_lookup should include any for or while loop, and the block of each procedure should be no more than 6 lines of code
Seriously, cheating is lame.