I was doing some leetcode problems and found that I couldn't carry my variables through recursive functions as I thought I could.
So for example, say I wanted to sum all of nodes of a tree.
So I thought of implementing it this way:
def Sum(root):
def dfs(root,x):
if root:
dfs(root.left, x)
x.append(root.val)
dfs(root.right,x)
return x
return(sum(dfs(root,x=[])))
And this works. However, say I want to cut down on memory, how come this implementation doesn't work and just returns the root node.
def Sum(root):
def dfs(root,x):
if root:
dfs(root.left, x)
x+=(root.val)
dfs(root.right,x)
return x
return(sum(dfs(root,x=0)))
Any help or guidance would be appreciated.
x is mutable in your first definition; each call to dfs gets a reference to the same list.
In your second example, x is immutable. The value of x is not modified by the recursive call; x += root.val just updates the local copy of the argument.
Instead, you need to add the return value of dfs directly to x.
def Sum(root):
def dfs(root, x):
if root:
x += dfs(root.left, x)
x += root.val
x += dfs(root.right,x)
return x
return dfs(root, x=0)
There's no need to define dfs, since you aren't really doing a generic search or walk any more. Just call Sum recursively. Also, the return value is sufficient; you don't need an x argument at all.
def Sum(root):
if not root:
return 0
else:
return Sum(root.left) + root.val + Sum(root.right)
Related
I am looking at this coding question:
Write a function that takes in a tree and returns the maximum sum of the values along any path in the tree. Recall that a path is from the tree's root to any leaf.
The following boilerplate code is provided with it:
def tree(root_label, branches=[]):
for branch in branches:
assert is_tree(branch)
return [root_label] + list(branches)
def label(tree):
return tree[0]
def branches(tree):
return tree[1:]
def is_tree(tree):
if type(tree) != list or len(tree) < 1:
return False
for branch in branches(tree):
if not is_tree(branch):
return False
return True
def is_leaf(tree):
return not branches(tree)
def max_path_sum(t):
"""Return the maximum path sum of the tree.
>>> t = tree(1, [tree(5, [tree(1), tree(3)]), tree(10)])
>>> max_path_sum(t)
11
"""
"*** YOUR CODE HERE ***"
How can I define the max_path_sum function recursively using these pre-defined functions?
Call the function recursively for the branches and add the current node's label to the maximum of those sub-results:
def max_path_sum(t):
return label(t) + max(map(max_path_sum, branches(t)), default=0)
The default argument covers the case where t is a leaf, in which case the result will just be the node's label.
You could also call is_leaf to make the distinction, but it makes the code longer:
def max_path_sum(t):
if is_leaf(t):
return label(t)
return label(t) + max(map(max_path_sum, branches(t)))
I found a solution to Leetcode NO. 543 Diameter of Binary Tree which is solved with the use of global variables. I have the solution shown in the text below. The author used a scalar variable, 'self.res', to store the final answer which is updated when the program traverses through the given binary tree.
I am wondering why the author needs to use self.res rather than a generic integer variable---for example, res only---to store the answer; when I replace self.res with res, the answer is wrong. Can anyone point out the difference?
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
self.res = 0
def depth(root):
if not root:
return 0
left = depth(root.left)
right = depth(root.right)
self.res = max(self.res, left + right)
return max(left, right) + 1
depth(root)
return self.res
Strictly speaking, it doesn't have to be an attribute. It could be a non-local variable.
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
res = 0
def depth(root):
nonlocal res
if not root:
return 0
left = depth(root.left)
right = depth(root.right)
res = max(res, left + right) # the key to memorize the result
return max(left, right) + 1
depth(root)
return res
Without the nonlocal statement, res would be a local variable that isn't set the first time depth tries to use it in the call to max.
Python 2 did not have a nonlocal statement, so an instance attribute would have been the best alternative to a global variable for persisting state between calls to depth. (The type hints indicate this probably wasn't written for Python 2, but old habits can die hard.) In Python 3, using nonlocal, the above no longer even uses self, so diameterOfBinaryTree can trivially be written as a regular function rather than an instance method of an unnecessary class.
I think my question should be more clearly understood by this short code:
fs = []
for k in range(0, 10):
def f(x):
return x + 2*k
fs.append(f)
fs[0](1)
# expecting 1 but 19(=1+2*9)
How do I instead make f return what I want? Please note that f cannot receive k as an argument.
(What I'm actually trying to do is prepare multiple constraint functions that are fed to scipy.optimize.minimize)
The typical way to fix this is to do something like:
def f(x, k=k):
return x + 2*k
For the most part, this shouldn't affect your "f cannot receive k as an argument" condition because it isn't a required argument.
A related, but different approach would be to define f out of the loop.
def f(k, x):
return x + 2*k
Then in the loop use functools.partial.
import functools
fs = []
for k in range(10):
fs.append(functools.partial(f, k))
In this approach, your function won't accept a value for k even if you try to pass one.
Basically the problem is that the variable k, in this case, continually changes as the loop iterates. This means that all things which are pointing to the variable "k" are pointing to the same value at all times.
There are a couple of ways to solve this. This is perhaps the most common.
def f(x, k=k):
# This sets k as a locally bound variable which is evaluated
# at the time the function is created.
return x + 2*k
The detriment is that this solution will allow a later function to call the newly created functions with a different value of k. This means you could call f("cat","dog") and get "catdogdog" as a return. While this is not the end of the world, it certainly isn't intended.
However, you could also do something like this:
def f_maker(k):
# Create a new function whose variable "k" does not exist in outside scope.
def f(x):
return x + 2*k
return f
fs = []
for k in range(0, 10):
fs.append(f_maker(k))
fs[0](1)
i would like to perform a calculation using python, where the current value (i) of the equation is based on the previous value of the equation (i-1), which is really easy to do in a spreadsheet but i would rather learn to code it
i have noticed that there is loads of information on finding the previous value from a list, but i don't have a list i need to create it! my equation is shown below.
h=(2*b)-h[i-1]
can anyone give me tell me a method to do this ?
i tried this sort of thing, but that will not work as when i try to do the equation i'm calling a value i haven't created yet, if i set h=0 then i get an error that i am out of index range
i = 1
for i in range(1, len(b)):
h=[]
h=(2*b)-h[i-1]
x+=1
h = [b[0]]
for val in b[1:]:
h.append(2 * val - h[-1]) # As you add to h, you keep up with its tail
for large b list (brr, one-letter identifier), to avoid creating large slice
from itertools import islice # For big list it will keep code less wasteful
for val in islice(b, 1, None):
....
As pointed out by #pad, you simply need to handle the base case of receiving the first sample.
However, your equation makes no use of i other than to retrieve the previous result. It's looking more like a running filter than something which needs to maintain a list of past values (with an array which might never stop growing).
If that is the case, and you only ever want the most recent value,then you might want to go with a generator instead.
def gen():
def eqn(b):
eqn.h = 2*b - eqn.h
return eqn.h
eqn.h = 0
return eqn
And then use thus
>>> f = gen()
>>> f(2)
4
>>> f(3)
2
>>> f(2)
0
>>>
The same effect could be acheived with a true generator using yield and send.
First of, do you need all the intermediate values? That is, do you want a list h from 0 to i? Or do you just want h[i]?
If you just need the i-th value you could us recursion:
def get_h(i):
if i>0:
return (2*b) - get_h(i-1)
else:
return h_0
But be aware that this will not work for large i, as it will exceed the maximum recursion depth. (Thanks for pointing this out kdopen) In that case a simple for-loop or a generator is better.
Even better is to use a (mathematically) closed form of the equation (for your example that is possible, it might not be in other cases):
def get_h(i):
if i%2 == 0:
return h_0
else:
return (2*b)-h_0
In both cases h_0 is the initial value that you start out with.
h = []
for i in range(len(b)):
if i>0:
h.append(2*b - h[i-1])
else:
# handle i=0 case here
You are successively applying a function (equation) to the result of a previous application of that function - the process needs a seed to start it. Your result looks like this [seed, f(seed), f(f(seed)), f(f(f(seed)), ...]. This concept is function composition. You can create a generalized function that will do this for any sequence of functions, in Python functions are first class objects and can be passed around just like any other object. If you need to preserve the intermediate results use a generator.
def composition(functions, x):
""" yields f(x), f(f(x)), f(f(f(x)) ....
for each f in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
yield x
Your specs require a seed and a constant,
seed = 0
b = 10
The equation/function,
def f(x, b = b):
return 2*b - x
f is applied b times.
functions = [f]*b
Usage
print list(composition(functions, seed))
If the intermediate results are not needed composition can be redefined as
def composition(functions, x):
""" Returns f(x), g(f(x)), h(g(f(x)) ....
for each function in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
return x
print composition(functions, seed)
Or more generally, with no limitations on call signature:
def compose(funcs):
'''Return a callable composed of successive application of functions
funcs is an iterable producing callables
for [f, g, h] returns f(g(h(*args, **kwargs)))
'''
def outer(f, g):
def inner(*args, **kwargs):
return f(g(*args, **kwargs))
return inner
return reduce(outer, funcs)
def plus2(x):
return x + 2
def times2(x):
return x * 2
def mod16(x):
return x % 16
funcs = (mod16, plus2, times2)
eq = compose(funcs) # mod16(plus2(times2(x)))
print eq(15)
While the process definition appears to be recursive, I resisted the temptation so I could stay out of maximum recursion depth hades.
I got curious, searched SO for function composition and, of course, there are numerous relavent Q&A's.
I want to create functions and add them to a list, reusing the same name every time.
def fconstruct():
flist = []
for x in xrange(0,5):
def kol():
return x
flist.append(kol)
del kol #this doesn't fix the problem.
return flist
k = fconstruct()
However, this fails, even if i delete the function every loop, and no matter which of the functions in k i call, the result is the the same: 4, because the newest definition of kol has changed all the previous ones. For a simple function such as this,
kol = lambda: x
would work. However, i need to do this for a much more complex function
As solutions, i could store the function as a string in the list and use exec to call it.
I could generate disposable and random function names:
fname = '_'+str(random.random())
exec fname + ' = kol'
exec 'flist.append('+fname+')'
I could play around with this implementation of multiline lambdas: https://github.com/whaatt/Mu
None of these seem elegant, so what is the preferred way of doing this?
You have to use another function that generates the function you want with the x parameter set. Here I use the kol_factory (see also the answer to Closures in Python):
def fconstruct():
flist = []
# create a function g with the closure x
def kol_factory(y):
# y is local here
def kol():
# kol uses the y
return y
return kol
for x in xrange(0,5):
# we create a new g with x "burned-in"
flist.append(kol_factory(x))
return flist
for k in fconstruct():
print k()
You can define the factory function factory outside the fconstruct function:
def kol_factory(y):
# y is local here
def kol():
# kol uses the y
return y
return kol
def fconstruct():
flist = []
for x in xrange(0,5):
# we create a new kol_factory with x "burned-in"
flist.append(kol_factory(x))
return flist
for k in fconstruct():
print k()
When you're defining kol, you're establishing a closure around x. In fact, each time through the loop you're getting a closure around the same variable.
So while you have 5 different functions all named kol, they all return the value of the same variable. When the loop is finished, that variable's value is 4, so each function returns 4.
Consider this:
def fconstruct():
flist = []
for x in range(5):
def get_kol(y):
def kol():
return y
return kol
flist.append(get_kol(x))
return flist
In this case, the function get_kol() returns a function who's return value is get_kol()'s argument.
The closure in kol() is now around y, which is local to the get_kol() function, not the loop. Each time get_kol() is called, a new local y is created, so each kol() gets a different variable closure.
An alternative way is to create a partial function with functools.partial. This accomplishes the same thing (creates a function which, when called executes another function with arguments), and is a lot more powerful
def f(a): # whatever arguments you like
return a
# create a bunch of functions that return f(x)
flist = [functools.partial(f, x) for x in range(5)]
def g(a, b):
return a + b
# create a bunch of functions that take a single argument (b), but have a set to
# 0..4:
flist = [functools.partial(g, x) for x in range(5)]
some_g = flist[0]
some_g(1) # returns 0 + 1