I'm studying for coding interviews and working with a lot of different data structures.
I'm relatively new to Tree problems and have been doing problems daily to practice.
It's one thing to have formulas committed to memory, and another to truly understand them. When I understand something it is easy to apply that understanding to more difficult problems.
Recursive solutions are a little harder for me to mentally visualize and while intuitively they make sense, I am trying to get a deep understanding of what's happening on the Stack.
I have a tree and want to do in order traversal. No problem.
data = []
def checkBST(root):
if root:
checkBST(root.left)
data.append(root.data)
checkBST(root.right)
print(data)
I created the data variable to print out what is being stored on each pass through the method.
It printed
[]
[1]
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
I am trying to logically look at what is happening and want to know if my Logic is correct.
There are 15 printed results and 7 Nodes. However we get to 15 because there are 8 places checked for Nodes where Node is None. That happens on Nodes 1, 3, 5, 7.
We are checking the left half of the tree before the right.
[]
#nothing stored because we move onto Node 2 as we don't hit the base case.
[1]
#1 stored because Node 1 doesn't have a left value. So we move onto the append call.
[1]
#1 returned because Node 1 doesn't have a right value.
[1, 2]
#2 stored because because we finished checking the left side and moved onto append data.
[1, 2, 3]
#3 is stored because we are calling the in order traversal on the right side of two now.
[1, 2, 3]
#3 is returned again because it doesn't have a root.left
[1, 2, 3]
#3 is returned again because it doesn't have a root.right
[1, 2, 3, 4]
# we hit the append method for 4, now we move onto the in order traversal on the right
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
The right side will be checked just like the left so I didn't write my logic as it'd be redundant.
I just want clarification if I am looking at this problem in the correct format.
Thanks for any help in understanding this!
The comments in the output are not always correct.
The first output ([]) happens when a function call reaches the end. The first call where this happens is when root is node 1 and from there the first recursive call is made. That call will have None as argument, and so it is the first time a call reaches the print statement.
So we have these ongoing calls:
checkBST(4)
checkBST(2) # left child of 4
checkBST(1) # left child of 2
checkBST(None) # left child of 1
print # --> []
When that deepest call finishes, the function with node 1 will append 1 to the data list, and then make the recursive call for the right child, which also is None and [1] is printed.
Here is a visualisation of the process. The columns represent the depth of the recursion, and the rows represent the sequence of events as time progresses (downwards). The last column is reserved for showing what the current value of data is. When it has a yellow background it means it is printed.
Light blue means that code is executed at that recursion depth. Darker blue means the corresponding function call is pending (on the stack), waiting for the nested recursive call to return.
From this image you can also see why the same output is sometimes repeated: it is printed at different recursion levels as the algorithm is backtracking.
Related
Say that the target isn't in the list. Instead of outputting -1, I want it to output the rightmost value that's less than the target, followed by the next value (if there is one). In other words, I want to see the gap where the target would be.
If there was a list [1, 2, 4, 7, 7, 8, 9] and I was looking for 5, instead of outputting -1 I want it to output [4, 7]. How do I do that?
Use bisect.bisect to find the insertion point for 5 using binary search, and then take the elements before and after that point:
>>> import bisect
>>> a = [1, 2, 4, 7, 7, 8, 9]
>>> i = bisect.bisect(a, 5)
>>> a[i-1:i+1]
[4, 7]
Can somebody tell me what's the difference between this code:
x = [1, 2, 3, 4, 5, 6, 7]
for i in x[:]:
if i == 5:
x.insert(0, i)
And this code:
x = [1, 2, 3, 4, 5, 6, 7]
for i in x:
if i == 5:
x.insert(0, i)
Why doesn't the second one work? I know it is mentioned in the Python tutorial, but I can't quite understand it.
In the first version, you create a copy (by slicing the list from the beginning to the end), in the second one you're iterating over the original list.
If you iterate over a container, its size can't change during iteration, for good reasons (see below). But since you call x.insert, the size of your list changes.
If you execute the second version, it actually doesn't throw an error immediately, but continues indefinitely, filling the list up with more and more 5s:
Once you're at the list index 4 (and i is therefore 5), you're inserting a 5 at the beginning of the list:
[5, 1, 2, 3, 4, 5, 6, 7]
You then continue in the loop, implicitly increasing your index to 5, which is now again 5, because the whole list got shifted one to the right, due to your insertion, so 5 will be inserted again:
[5, 5, 1, 2, 3, 4, 5, 6, 7]
This goes on "forever" (until there's a MemoryError).
Thanks for checking out my question, am using Python 3 by the way, here is the code:)
scale=[1,2,3,4,5,6]
MNP = {'scale degree' : []
}
for index, value in enumerate(scale):
scale.insert(len(scale),scale[0])
del scale[0]
MNP['scale degree'].append(scale[1])
print (MNP['scale degree'])
So, my goal here is append the modified versions of a list I called scale, into a dict I called MNP. The desired output is a list ('scale degree' that takes the original number of a list (such as scale), and moves it the end of the list, at the same time, all the numbers would shift one to the left, this is what is happens if I give the command to print the scale within the function:
for index, value in enumerate(scale):
scale.insert(len(scale),scale[0])
del scale[0]
MNP['scale degree'].append(scale[1])
print (MNP['scale degree'])
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6, 1]
[3, 4, 5, 6, 1, 2]
[4, 5, 6, 1, 2, 3]
[5, 6, 1, 2, 3, 4]
[6, 1, 2, 3, 4, 5]
Yet when I try to do so I encountered (yes, past tense) a problem with my understanding. See, if I execute the command:
print(scale[1])
Then it actually does print the numbers 2,3,4,5,6,1 . This is why I used the enumerate function, I thought that this may solve the problem. I thought that, maybe the index number determined somehow which list would be printed off, but this is of course is wrong, even though the output is identical, and, it's worth mentioning that am still very much a stargazed newbie. Yet I did some thinking and realized that it's merely printing off the second value of each modified list, the exact same as if I gave it a single command to print off only one version, yet being a disobedient little bugger if I ask it to append the whole blown thing.
Bloody Hell.
So, now, my question is, how do I append the modified version of the scale, and not just a single value?
Appending the scale as a whole does'st work by the way (this was also my first solution), as the output is then:
[[2, 3, 4, 5, 6, 1]]
[[3, 4, 5, 6, 1, 2], [3, 4, 5, 6, 1, 2]]
[[4, 5, 6, 1, 2, 3], [4, 5, 6, 1, 2, 3], [4, 5, 6, 1, 2, 3]]
it keeps going in this fashion until it reaches [1,2,3,4,5,6] * 6
Thanks in advance for any help, also if you may, could you recommend resources so that I can gain a basic understanding of what's playing behind the scenes? There's probably a lot I still don't understand (I mean in relation only to this problem alone, of course, in general am that close to understanding everything there is to know (haha)).
Thanks again
James
P.S how long in general should I wait till I seek help on SE? (For this particular problem, I've been dueling with if for a solid Day 1/2)
P.S.S A thanks to Borodin for pointing that the manipulation of data within a for loop is bad practice. How should this be correctly executed?
Is this the effect you're after?
>>> l = [1,2,3,4]
>>> l.append(list.pop())
[2,3,4,1]
Or if you want it unrolled a little:
>>> l = [1,2,3,4]
>>> e = list.pop()
>>> l.append(e)
[2,3,4,1]
In both cases, we remove the first element from the list and stick it on the end of the list - which I think is what you're after.
Or if you don't want to modify the original list:
>>> l = [1,2,3,4]
>>> l[1:]+[l[0]]
[2,3,4,1]
Here, we're just recombining slices - the original list is unchanged. Notice that I have to put l[0] into a list because that's the way + is implemented for lists - I can't do l[1:] + l[0].
I think this would help. It has rotate(n) which shifts the elements of the list by n places.
import collections
my_list = []
d = collections.deque([1,2,3,4,5])
for i in range(5):
d.rotate(-1)
my_list.append(d)
print my_list
Output:
[deque([1, 2, 3, 4, 5]), deque([1, 2, 3, 4, 5]), deque([1, 2, 3, 4, 5]), deque([1, 2, 3, 4, 5]), deque([1, 2, 3, 4, 5])]
I have a list of numbers, such as:
[1, 2, 3, 4, 5, 6]
I'm having trouble figuring out how to switch the first 2 items of the list with the last 2, or the first 3 with the last 3, and so on.
When i assign the values of the 1st two numbers to the last 2 items of the list, i then cannot assign the last 2 values (what used to be the last 2 values of the list) to the first two because the last 2 values have been lost.
If i try using another empty list and appending the last 2 values of the original list to that list, then appending the middle values, and then the first 2 values of the old list, I end up with something like this:
[[[5, 6], [3, 4], [1, 2]]]
I don't want nested lists! What I want is:
[5, 6, 3, 4, 1, 2]
Can someone help me?
>>> nums = [1, 2, 3, 4, 5, 6]
>>> nums[:2], nums[-2:] = nums[-2:], nums[:2]
>>> nums
[5, 6, 3, 4, 1, 2]
This modifies the original list but if you want a separate new list you should use the following:
>>> nums = [1, 2, 3, 4, 5, 6]
>>> swapped_nums = nums[-2:] + nums[2:-2] + nums[:2]
>>> swapped_nums
[5, 6, 3, 4, 1, 2]
Note: This won't work properly if your list has < 4 elements
I have a group of buckets, each with a certain number of items in them. I want to make combinations with one item from each bucket. The loop should keep making different combinations until each item has participated in at least some defined number.
I can easily see how to run the loop and stop once a single element has been accessed a certain number of times. However I can't see how to set a minimum cutoff point beyond searching through all the elements in all the buckets to check their access number after every iteration of the loop.
itertools.product is one way (a very systematic one) to make the "combinations" you request (don't confuse with the .combinations function of course) -- or you could make them randomly with random.choose from each bucket; not sure which one is for you since I don't know what your real purpose is.
Anyway, I'd keep track of how many combos each item has been in with a dict (or one dict per bucket, if there can be overlap in items among buckets). Or, you could use a collections.Counter in Python 2.7, if that's your version.
At any rate, one possibility to do what you request is: the moment an item's count reaches N, remove that item from its bucket (or all buckets, if there's overlap and that's the semantics you require) -- except that if this leaves the bucket empty, restore the bucket's contents and mark that bucked as "done" (you don't need to remove items from a done bucket) e.g. by adding the bucket's index to a set.
You're done when all buckets are done (whether it be randomly or systematically).
Need some code to explain this better? Then please specify the overlap semantics (if overlap is possible) and the systematic-or-random requirements you have.
try
visits = defaultdict(int)
# do at each node visiting
visits[n] += 1
if visits[n] >= MAX_VISITS:
break
print 'done'
Use a dictionary with the items as keys. Every time the item is used, update its count. Then check to see whether all the values are at least above the threshold, ie:
counter = dict()
while min(counter.values) < threshold:
# make a combination
# and update the dictionary
In vanilla Python, this seems to do the job:
buckets = [ [1,2,3],[4],[5,6],[7,8,9,0] ]
def combo(b, i = 0, pref = []):
if len(b) > i:
c = b[i]
for v in c:
combo(b, i + 1, pref + [v])
else:
print pref
combo(buckets)
Output:
[1, 4, 5, 7]
[1, 4, 5, 8]
[1, 4, 5, 9]
[1, 4, 5, 0]
[1, 4, 6, 7]
[1, 4, 6, 8]
[1, 4, 6, 9]
[1, 4, 6, 0]
[2, 4, 5, 7]
[2, 4, 5, 8]
[2, 4, 5, 9]
[2, 4, 5, 0]
[2, 4, 6, 7]
[2, 4, 6, 8]
[2, 4, 6, 9]
[2, 4, 6, 0]
[3, 4, 5, 7]
[3, 4, 5, 8]
[3, 4, 5, 9]
[3, 4, 5, 0]
[3, 4, 6, 7]
[3, 4, 6, 8]
[3, 4, 6, 9]
[3, 4, 6, 0]
There is no doubt a more Pythonic way of doing it.