Subtracting branches of a Binary Number Tree in python - python

So like I have this problem and I have no idea how to do it at all. The problem goes like this:
Define a recursive function called subt_tree() that takes a Binary-Number-Tree and recursively subtracts the value of each right branch from the left branch. So for example, if
tree1 = (25,((10,4),(12,11)))
then subt_tree(tree1) would return
( 25 - ( (10-4) - (12-11) ) ) = ( 25 - ( 6 - 1 ) ) = ( 25 - 5 ) = 20.
So essentially I have to make each tuple into a subtraction problem and then solve.
I've tried this:
def subt_tree(bnt):
"""Takes a bnt and recursively subtracts the value of each right branch from the left branch.
bnt -> number"""
if not isinstance(bnt,tuple):
return 1
else:
return subt_tree(bnt[0]) - subt_tree(bnt[1])
but there must be something wrong in my else statement because no matter what I input it will only return 0 or 1.

Instead of returning 1 why don't you return the value itself? That is after all the base case for your recursion.
i.e.
def subt_tree(bnt):
if not isinstance(bnt,tuple):
return bnt
else:
return subt_tree(bnt[0]) - subt_tree(bnt[1])
If you return 1 you'll only ever get a set of values consisting of 1 being subtracted from each other.

Related

Recursive function return value without allocating extra space?

So I'm stuck at trying to optimize this LeetCode problem called Frog Jump. Here's the basic description of the problem:
Given a list of stones' positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.
If the frog's last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.
e.g: [0,1,3,5,6,8,12,17]
There are a total of 8 stones. The first stone at the 0th unit, second
stone at the 1st unit, third stone at the 3rd unit, and so on... The
last stone at the 17th unit.
Return true. The frog can jump to the last stone by jumping 1 unit
to the 2nd stone, then 2 units to the 3rd stone, then 2 units to the
4th stone, then 3 units to the 6th stone, 4 units to the 7th stone,
and 5 units to the 8th stone.
Here's my solution which works. What I need help with is how to output the same boolean without allocating the extra res array which stores the logical OR of all the explored paths using DFS.
class Solution:
def canCross(self, stones: List[int]) -> bool:
if stones[1] != 1:
return False
res = []
memo = {}
def dfs(curr_stone, last_stone, last_jump):
if curr_stone == last_stone:
res.append(True)
return
if curr_stone > last_stone:
res.append(False)
return
for i in range(-1,2):
next_stone = curr_stone + (last_jump + i)
if next_stone in stones and next_stone > curr_stone and (next_stone, last_stone, last_jump+i) not in memo:
memo[(next_stone, last_stone, last_jump+i)] = 1
dfs(next_stone, last_stone, last_jump+i)
dfs(1, stones[-1], 1)
return any(res)
Can someone help me with how to approach these questions? I always struggle a lot with these sort of questions and end up storing values in an array; however, ideally I would like the result of the recursive code to be the same without allocating the extra res array space.
Since the entire purpose of the function seems to boil down to return any(res), it seems like you should return True/False from the recursive function instead of appending them, then exit from all recursive calls once a single True value is found, and not bother saving every found value.
That will involve checking what was returned from the recursive call dfs(next_stone, last_stone, last_jump+i), and if it's true, simply returning that True:
from typing import List
class Solution:
def canCross(self, stones: List[int]) -> bool:
if stones[1] != 1:
return False
memo = {}
def dfs(curr_stone, last_stone, last_jump):
if curr_stone == last_stone:
return True # Return the results instead of appending them to a list
if curr_stone > last_stone:
return False
for i in range(-1, 2):
next_stone = curr_stone + (last_jump + i)
if next_stone in stones and next_stone > curr_stone and (next_stone, last_stone, last_jump + i) not in memo:
memo[(next_stone, last_stone, last_jump + i)] = 1
rec_result = dfs(next_stone, last_stone, last_jump + i)
if rec_result: # Then check the recursive results at the call-site
return True
return dfs(1, stones[-1], 1)
I'll note, I haven't done extensive testing on this, but from some quick "head interpretation", it seems to be equivalent.

Maximum Path Sum between 2 Leaf Nodes(GeeksForGeeks)

Given a binary tree in which each node element contains a number. Find the maximum possible sum from one leaf node to another.
Example 1:
Input :
3
/ \
4 5
/ \
-10 4
Output: 16
Explanation :
Maximum Sum lies between leaf node 4 and 5.
4 + 4 + 3 + 5 = 16.
Example 2:
Input :
-15
/ \
5 6
/ \ / \
-8 1 3 9
/ \ \
2 -3 0
/ \
4 -1
/
10
Output : 27
Explanation:
The maximum possible sum from one leaf node
to another is (3 + 6 + 9 + 0 + -1 + 10 = 27)
This is the solution:
'''
# Node Class:
class Node:
def _init_(self,val):
self.data = val
self.left = None
self.right = None
'''
res = -999999999
def maxPathSumUtil(root):
global res
if root is None:
return 0
if root.left is None and root.right is None:
return root.data
ls=maxPathSumUtil(root.left)
rs=maxPathSumUtil(root.right)
if root.left and root.right:
res=max(res,ls+rs+root.data)
return max(ls+root.data,rs+root.data) #Line: Problem
if root.left is None:
return rs+root.data
else:
return ls+root.data
def maxPathSum(root):
global res
res = -999999999
maxPathSumUtil(root)
return res
Can anyone tell me why do we use return max(ls+root.data,rs+root.data). And if we do use return max(ls+root.data,rs+root.data) for checking the maximum value then why do we use res=max(res,ls+rs+root.data) and not just res = max(ls+root.data,rs+root.data).
EDIT:
For example:
Let's take this tree for example:
10
/ \
8 2
/ \
3 5
In this, after recursive calls, ls becomes 3 and rs becomes 5.
res becomes ls+rs+root.data which is 3+5+8 = 16.
Then return max(ls+root.data,rs+root.data) which is max(11,13) = 13.
Now after this according to me the function should just return 13 but that does not happen. Even though return is not a recursive statement. How is the control flow of the code happening?
There are two things that are measured in parallel during execution:
ls+rs+root.data is the max path in the tree rooted by root, between two of the leaves below it. So it is (the value) of a leaf-to-leaf path
The function return value is the maximum path from root to any of the leaves below it. So it is (the value) of a root-to-leaf path
These are two different concepts and should not be mixed up.
Both ls and rs are function return values: ls represents the maximum path from root.left to a leaf. And in the same way rs represents the maximum path from root.right to a leaf.
ls+rs+root.data on the other hand, represents a path from leaf to leaf passing through root.
res should be updated if that latter expression is greater than res, hence the max().
But the function's return value should not represent a leaf-to-leaf path, but a root-to-leaf path. So that is why we have:
return max(ls+root.data,rs+root.data)
This tells the caller what the maximum root-to-leaf path is, not what the maximum leaf-to-leaf path is. The latter is used for determining res, not the function's return value.
I hope this clarifies the distinction between these two concepts and the roles they play in the algorithm.
The example
You presented this tree as example:
10
/ \
8 2
/ \
3 5
Indeed, when the function is called for the node 8, it:
sets res to 16 (the max path between two leaves below the node)
returns 13 (the max path from the node to one of its leaves)
You then ask:
Now after this according to me the function should just return 13 but that does not happen.
But it does happen like that. You should however not forget that this is the return value of maxPathSumUtil, not of maxPathSum. Also, this is not the top-level call of maxPathSumUtil. The value 13 is returned to another execution context of maxPathSumUtil, where root is the node 10. Then -- after another recursive call is made (with root equal to node 2), this top-level execution of the function maxPathSumUtil will:
set res to 25 (the max path between two leaves below the node 10)
return 23 (the max path from the node 10 to one of its leaves)
This toplevel call was made from within maxPathSum, which ignores the value returned by maxPathSumUntil.
It only takes the value of res (25), and returns that:
maxPathSumUtil(root) # notice that return value is ignored.
return res
At each node, we have to check whether that node's left and right child resulted in max path. But when we return, we need to return either the left or right path depending upon whichever is max.
Let's take this tree for example:
10
/ \
8 2
/ \
3 5
In this, after recursive calls, ls becomes 3 and rs becomes 5. res becomes ls+rs+root.data which is 3+5+8 = 16. So res(result) will be updated to 16, and return will be max(11,13) which is 13. Now this 13 value will be used by node 10 as ls(left value).

Balanced parentheses parser Python

I am trying to make a balanced parentheses parser by using recursion and produce a tree.
For example, if you pass in '()()' the tree would be constructed like this
step 1
B
|
empty
step 2
B
/ | \ \
( empty ) B
|
empty
step 3
B
/ | \ \
( empty ) B
/ | \ \
( empty ) B
|
empty
Right now, my code "kind of" work for a legit input like '()()', but it is supposed to give me False for something like '())('. It is not returning False. Can I get help with this?
class Node:
def __init__(self, label):
self.label = label
self.leftmostChild = None
self.rightSibling = None
def makeNode0(x):
root = Node(None)
root.label = x
return root
def makeNode1(x, t):
root = makeNode0(x)
root.leftmostChild = t
return root
def makeNode4(x, t1, t2, t3, t4):
root = makeNode1(x, t1)
t1.rightSibling = t2
t2.rightSibling = t3
t3.rightSibling = t4
return root
nextTerminal = "())("
def B(index):
firstB = Node(None)
secondB = Node(None)
if index != len(nextTerminal):
if nextTerminal[index] == '(':
index += 1
firstB = B(index)
if firstB is not False and nextTerminal[index] == ')':
index += 1
secondB = B(index)
if secondB is False:
return False
else:
return makeNode4('B', makeNode0('('), firstB, makeNode0(')'), secondB)
else:
return False
else:
return makeNode1('B', makeNode0('emp'))
b = B(0)
I'm going to outline a second approach here, in the hopes that it provides you with some insight into why your current program isn't working. To be frank, I'm not certain what's going on - I initially thought that each right sibling indicated an additional parenthetical statement, but it seems like the tree's structure is hardcoded, regardless of the parentheses. My suggestion would be to start from the below solution and work your way towards creating these trees.
Keep track of a variable depth.
For every start parenthesis, increment depth by 1.
For every end parenthesis, decrement depth by 1. If depth is negative, we have encountered an end parenthesis too soon -- return false.
After processing all parentheses, check that depth is 0. Otherwise, we had too many start parentheses.

Error in Python Binary Search Algorithm when using pseudocode

So I'm trying to make a recursive binary search algorithm and here is the pseudocode I'm using:
BINARY-SEARCH(X, A, start, end)
1 if start > end then
2 return False
3 middle = ((end - start) / 2) + start
4 if X = A[middle] then
5 return True
6 else if X < A[middle] then
7 return BINARY-SEARCH(X, A, start, middle - 1)
8 else
9 return BINARY-SEARCH(X, A, middle + 1, end)
and here's my program:
def binarySearchRec(value, list, start, end):
if start > end:
return False
middle = ((end - start) / 2) + start
if value == list[middle]:
return True
elif value < list[middle]:
return binarySearchRec(value, list, start, middle - 1)
else:
return binarySearchRec(value, list, middle + 1, end)
and so I keep getting an index error whenever I use a value that is not in the list, but it works fine for finding values that are in the list, any help would be greatly appreciated
Are you using 'start' and 'end' properly? I just ran your function and it works well for values not in the list (False is returned).
Since the answer has been given away already I suggest you try to approach the problem from another angle - by testing it:
whenever I use a value that is not in the list, but it works fine for finding values that are in the list
Interestingly the code does not fail on every number not in the array. Try with array = range(1,10,2) and search e.g. 2, 4, 6, 8 -- all not in the array. It will work. Search 10 and it will fail. That's a hint that something is probably wrong with limit checking, rather than the implementation as such.
any help would be greatly appreciated
Here is a way to test your function and quickly see on what numbers it is failing:
from itertools import izip_longest as izipl
def complement(a):
return list(set(range(min(a), max(a) + 10)) - set(a))
array = range(1,10,2)
c_array = complement(array)
start = 0
end = len(array) # that's the culprit
try:
for a,b in izipl(array, c_array):
if a:
assert binarySearchRec(a, array, start, end), "expected to find %s" % a
if b:
assert not binarySearchRec(b, array, start, end), "did not expect to find %s" % b
print "worked on", a, b
except:
print "failed on", a, b
else:
print "all is well"
=>
worked on 1 2
worked on 3 4
worked on 5 6
worked on 7 8
failed on 9 10

Python method only works once

I'm writing a method for calculating the covariance of 2 to 8 time-series variables. I'm intending for the variables to be contained in list objects when they are passed to this method. The method should return 1 number, not a covariance matrix.
The method works fine the first time it's called. Anytime it's called after that, it returns a 0. An example is attached at the bottom, below my code. Any advice/feeback regarding the variable scope issues here would be greatly appreciated. Thanks!
p = [3,4,4,654]
o = [4,67,4,1]
class Toolkit():
def CovarianceScalar(self, column1, column2 = [], column3 = [], column4 = [],column5 = [],column6 = [],column7 = [],column8 = []):
"""Assumes all columns have length equal to Len(column1)"""
#If only the first column is passed, this will act as a variance function
import numpy as npObject
#This is a binary-style number that is assigned a value of 1 if one of the input vectors/lists has zero length. This way, the CovarianceResult variable can be computed, and the relevant
# terms can have a 1 added to them if they would otherwise go to 0, preventing the CovarianceResult value from incorrectly going to 0.
binUnityFlag2 = 1 if (len(column2) == 0) else 0
binUnityFlag3 = 1 if (len(column3) == 0) else 0
binUnityFlag4 = 1 if (len(column4) == 0) else 0
binUnityFlag5 = 1 if (len(column5) == 0) else 0
binUnityFlag6 = 1 if (len(column6) == 0) else 0
binUnityFlag7 = 1 if (len(column7) == 0) else 0
binUnityFlag8 = 1 if (len(column8) == 0) else 0
# Some initial housekeeping: ensure that all input column lengths match that of the first column. (Will later advise the user if they do not.)
lngExpectedColumnLength = len(column1)
inputList = [column2, column3, column4, column5, column6, column7, column8]
inputListNames = ["column2","column3","column4","column5","column6","column7","column8"]
for i in range(0,len(inputList)):
while len(inputList[i]) < lngExpectedColumnLength: #Empty inputs now become vectors of 1's.
inputList[i].append(1)
#Now start calculating the covariance of the inputs:
avgColumn1 = sum(column1)/len(column1) #<-- Each column's average
avgColumn2 = sum(column2)/len(column2)
avgColumn3 = sum(column3)/len(column3)
avgColumn4 = sum(column4)/len(column4)
avgColumn5 = sum(column5)/len(column5)
avgColumn6 = sum(column6)/len(column6)
avgColumn7 = sum(column7)/len(column7)
avgColumn8 = sum(column8)/len(column8)
avgList = [avgColumn1,avgColumn2,avgColumn3,avgColumn4,avgColumn5, avgColumn6, avgColumn7,avgColumn8]
#start building the scalar-valued result:
CovarianceResult = float(0)
for i in range(0,lngExpectedColumnLength):
CovarianceResult +=((column1[i] - avgColumn1) * ((column2[i] - avgColumn2) + binUnityFlag2) * ((column3[i] - avgColumn3) + binUnityFlag3 ) * ((column4[i] - avgColumn4) + binUnityFlag4 ) *((column5[i] - avgColumn5) + binUnityFlag5) * ((column6[i] - avgColumn6) + binUnityFlag6 ) * ((column7[i] - avgColumn7) + binUnityFlag7)* ((column8[i] - avgColumn8) + binUnityFlag8))
#Finally, divide the sum of the multiplied deviations by the sample size:
CovarianceResult = float(CovarianceResult)/float(lngExpectedColumnLength) #Coerce both terms to a float-type to prevent return of array-type objects.
return CovarianceResult
Example:
myInst = Toolkit() #Create a class instance.
First execution of the function:
myInst.CovarianceScalar(o,p)
#Returns -2921.25, the covariance of the numbers in lists o and p.
Second time around:
myInst.CovarianceScalar(o,p)
#Returns: 0.0
I belive that the problem you are facing is due to mutable default arguments. Basicily, when you first execute myInst.CovarianceScalar(o,p) all columns other than first two are []. During this execution, you change the arguments. Thus when you execute the same function as before, myInst.CovarianceScalar(o,p), the other columns in the arguments are not [] anymore. They take values of whatever value they have as a result of the first execution.

Categories

Resources