A function f is defined by the rule that
Write a function f(n) that computes f by an iterative process
I wrote this. and still not getting it right. Please advise how to fix it.
def f(n):
if (n<3):
return n
else:
for x in range (n):
a = f(n-1) + 2*f(n-2) + 3*f(n-3)
return (a)
Simply use a memory cache:
def f(n):
if n < 3:
return n
a,b,c = 0,1,2
for i in range(n-2):
a,b,c = b,c,c+2*b+3*a
return c
In this function we use a to denote f(n-3), b to denote f(n-2) and c for f(n-1), at each iterative step, we calculate f(n) and thus we shift: a becomes b, b becomes c and c obtains the new value. We do this until we have reached the requested n.
So initially we will calculate f(3). In that case, a is f(0)=0, b is f(1)=1, and c is f(2)=2. Now after that iteration, a takes f(1)=1, b takes f(2)=2, and c takes f(3)=f(2)+2×f(1)+3×f(0)=5, and you keep doing that until c has the right n.
This will work faster since in the recursive variant, you call for f(n-2) and f(n-1), but f(n-1) will on his way call for f(n-2) thus introducing duplicated work.
If you want the function to return first n elements, you can use simple dynamic programming with memoization with O(n) space and time:
def F(n):
f = [0]*n
f[:4] = range(4)
for i in range(4, n):
f[i] = f[i-1] + f[i-2] + f[i-3]
return f
print F(20)
# [0, 1, 2, 3, 6, 11, 20, 37, 68, 125, 230, 423, 778, 1431, 2632, 4841, 8904, 16377, 30122, 55403]
Related
I am trying to get all the surrounding integers of a given one, starting from the actual integer and going outwards from both sides at a time, for example:
generateNeighborhood(10, 3), where 10 is the origin and 3 the radius of the neighbourhood, should return [10,11,9,12,8,13,7].
My attempt so far is this:
def generateNeighborhood(c: int, r: int):
yield c
for i in range(1, r + 1):
for j in range(2):
yield c + i * (-1) ** j
Do you know any simpler ways of achieving these results?
A.
Here's a simple one-liner:
>>> c, r = 10, 3
>>> sorted(range(c-r, c+r+1), key=lambda n: (abs(c-n), -n))
[10, 11, 9, 12, 8, 13, 7]
range() can easily give us the numbers we need but to get them in the right order, sort each by its distance from the center c, using abs(). And to get the larger neighbour before the smaller in that pair (11 before 9), use -n which is more negative (smaller) for the larger neighbours.
If you want the smaller neighbour before the larger one, then flip the sign:
>>> sorted(range(c-r, c+r+1), key=lambda n: (abs(c-n), n))
[10, 9, 11, 8, 12, 7, 13]
In a generator:
def generateNeighborhood(c: int, r: int):
yield from sorted(range(c-r, c+r+1), key=lambda n: (abs(c-n), -n))
But note that sorted() returns a list anyway, so may as well put return sorted(...). And for very very long lists (large radii r), use (B) a modified version of your original code or (C) the variation below it:
B.
As user3386109 suggested in the comments, you can remove the j loop and yield the neighbours for that radius:
def generateNeighborhood(c: int, r: int):
yield c
for i in range(1, r + 1):
yield c + i
yield c - i
C.
Here's a variation, with generator expressions:
def generateNeighborhood(c: int, r: int):
yield c
pairs = ((c + i, c - i) for i in range(1, r + 1)) # generator, not expanded here
yield from (n for pair in pairs for n in pair) # processed one at a time
Performance with small and large radii:
Small: list(generateNeighborhood(10, 3)) - B is faster than A is faster than C
B: 1.19 µs
A: 2.53 µs
C: 2.6 µs
Large: list(generateNeighborhood(10, 3_000_000)) - B is faster than C is faster than A:
B: 877 ms
C: 1.43 s
A: 2.97 s
So for simplicity, go with A. For speed, go with B. (I thought C would beat B but it doesn't.)
These are both variants I could come up with. Decide for yourself if you think one is better. The problem is if you want to generate 1, -1 and 2, -2 at the same part of the loop, you would get a nested list. Therefore, you need to flatten it like I did with itertools. Also, in the first method, 0 is generated twice, therefore I need to skip one 0 by starting at index 1.
def generateNeighborhoodA(c: int, r: int):
li = list(itertools.chain.from_iterable((-i, i) for i in range(r + 1)))
for i in range(1, len(li)):
yield li[i] + c
def generateNeighborhoodB(c: int, r: int):
yield c
for i in range(1, r + 1):
yield c + i
yield c - i
If the order of elements wouldn't matter, this would be super short.
An efficient way of calculating this is vectorizing the operations. You can use numpy and the zip function to generate your result:
import numpy as np
def generateNeighborhood(c: int, r: int):
return np.hstack((np.array(c), np.array(list(zip(np.array(c) + np.array(range(1, r+1)), np.array(c) - np.array(range(1, r+1))))).ravel())).tolist()
The surrounding integer arrays are combined using zip so that they are arranged as requested, and then horizontally stacked with the central value. If you don't need the result as a list, simply remove the .tolist() at the end of the function.
Here is a neat way to do it with NumPy (or without Numpy, as in comments). Just replace the np.arange with the list comprehensions in comments to avoid numpy.-
def generateNeighborhood(n, m):
#Get elements front and behind
f = np.arange(n+1,n+m+1) #[i for i in range(n+1, n+m+1)]
l = np.arange(n-m,n+1) #[i for i in range(n-m, n+1)]
#Alternating merge between 2 lists
result = [None]*(len(l)+len(f))
result[::2] = reversed(l)
result[1::2] = f
print(result)
generateNeighborhood(10,3)
[10, 11, 9, 12, 8, 13, 7]
I am trying to write code which gives you numbers which are less than given or entered number , and their GCD equal to 1 . I wrote this code but I don't know if works or why not . For example I chose number 6. array will be like [1,2,3,4,5]. And my point is to filter numbers that GCD equals to 1. So it will be [1,5]. And their amount is two.
a is input number and b is list numbers that are less than entered one and not equal to zero . And then print it .
a = int(input("enter number \n"))
b = list(range(1,a))
print (b)
Then I convert list to array
for i in range(1, len(b)):
b[i] = int(b[i])
and then this
r = a % b[i]
q = int ( a / b[i])
while(r!=0):
a = b[i]
b[i] = r
q = int ( a / b[i])
r = a - (b[i] * q)
print ( a , b[i], r )
break
I am beginner .
A few comments about your code:
You should always encapsulate code like this in a function; write a function find_coprimes which takes an argument n and returns the list you want;
In order to test the correctness of your function, write a reference function find_coprimes_ref which does the same thing, but uses library functions to make sure there is no error; this will teach you to look for relevant library functions, and you can compare the results of the two functions;
The initial loop for i in range(1, len(b)): b[i] = int(b[i]) is wrong for two reasons; 1) It has no effect, as b is already a list of integers. 2) Lists are 0-indexed, so a correct iterations on every element of b would be for i in range(0, len(b)): or simply for i in range(len(b)):;
Your code has two nested loops: a while-loop executing repeatedly inside a for-loop; whenever there are nested loops like this, you must make sure that variables are reinitialised the way you intend them to at the beginning of the outer loop; in your case, variable a is modified inside the while-loop, and as a result, its value is wrong at the beginning of the next iteration of the for-loop.
The break statement at the end of the while-loop makes no sense; in general, break statements only make sense if they are encapsulated in an if conditional, and they act as a substitute for the loop condition; but it's always possible to write loops without using break at all and I recommend you forget about break entirely.
After performing the gcd calculation using q and r, your code is missing something to tell it whether or not to keep b[i] or not in the final result;
For integer division in python, it is better to use // rather than int(... / ...).
Code
import math
def find_coprimes_ref(n):
return [x for x in range(1,n) if math.gcd(x,n) == 1]
def find_coprimes(n):
result = []
for x in range(1, n):
a = n
b = x
r = a % b
q = a // b
while (r > 1):
a = b
b = r
q = a // b
r = a - b * q
if (r == 1):
result.append(x)
return result
# TESTING
for n in range(1, 31):
coprimes_ref = find_coprimes_ref(n)
coprimes = find_coprimes(n)
if coprimes_ref != coprimes:
print(n, coprimes_ref, coprimes)
Note how my code never modifies n or x in the loop; instead, I make copies called a and b and modify the copies.
Encapsulating even further
Note how function find_coprimes_ref is so much easier to read than function find_coprimes? This is not just because we used library function math.gcd. It's because library function math.gcd is a cleanly-encapsulated function with a name that explains clearly what it does. Your code contains a while loop inside a for loop and it's a bit hard to keep track of every variable and everything that is going on and not lost track of our sub-objective and overall objective.
To make your function both easier to read, easier to code and easier to debug, You should encapsulate the gcd calculation inside a function called gcd:
def gcd(a, b):
r = a % b
q = a // b
while (r > 1):
a = b
b = r
q = a // b
r = a - b * q
return r
def find_coprimes(n):
result = []
for x in range(1, n):
if gcd(a, b) == 1:
result.append(x)
return result
# TESTING GCD
for b in range(1, 31):
for a in range(b, 31):
r1 = math.gcd(a, b)
r2 = gcd(a, b)
if r1 != r2:
print(a, b, r1, r2)
# TESTING FIND_COPRIMES
for n in range(1, 31):
coprimes_ref = find_coprimes_ref(n)
coprimes = find_coprimes(n)
if coprimes_ref != coprimes:
print(n, coprimes_ref, coprimes)
There are two reasons why the code is easier to debug now:
The logic for gcd and for find_coprimes is cleanly separated, which means you can reason about gcd clearly without any risk of messing up the list and the other variables used in find_coprimes;
You can test separately your function gcd and your function find_coprimes; and if something doesn't work correctly, you'll know more precisely where to look for the issue rather than just thinking "well, something is wrong somewhere in the code but I have no idea where".
There are a few errors in your code like, break inside while loop. I have refactored your code and also added inbuilt math.gcd function to compare results.
import math
def math_inbuilt_gcd(a, b):
gcd_one = []
for x in b:
if math.gcd(x, a) == 1:
gcd_one.append(x)
print("gcd_one_math_fun:", gcd_one)
def gcd_my_fun(a, b):
gcd_arr = []
for i in range(len(b)):
x, y = a, b[i] # taking x, y just to make things clear
r = x % y # remainder
q = int(x / y) # quotient
while(r != 0):
x = y
y = r
q = int(x/y)
r = x % y
if y == 1:
gcd_arr.append(b[i])
print("gcd_one_my_fun:", gcd_arr)
a = int(input("Enter number: "))
b = list(range(1, a))
print("b:", b)
math_inbuilt_gcd(a, b)
gcd_my_fun(a, b)
Output:
Enter number: 10
b: [1, 2, 3, 4, 5, 6, 7, 8, 9]
gcd_one_math_fun: [1, 3, 7, 9]
gcd_one_my_fun: [1, 3, 7, 9]
I've got a function that has two recursive calls and I'm trying to convert it to an iterative function. I've got it figured out where I can do it with one call fairly easily, but I can't figure out how to incorporate the other call.
the function:
def specialMultiplication(n):
if n < 2:
return 1
return n * specialMultiplication(n-1) * specialMultiplication(n-2)
If I just had one of them, it would be really easily:
def specialMult(n, mult = 1):
while n > 1:
(n, mult) = (n-1, n * mult) # Or n-2 for the second one
return mult
I just can't figure out how to add the second call in to get the right answer overall. Thanks!
If you don't mind changing the structure of your algorithm a bit more, you can calculate the values in a bottom-up fashion, starting with the smallest values.
def specialMultiplication(max_n):
a = b = 1
for n in range(1, max_n+1):
a, b = b, a*b*n
return b
Convert the recursion to an iterative function using an auxiliary "todo list":
def specialMultiplication(n):
to_process = []
result = 1
if n >= 2:
to_process.append(n)
while to_process: # while list is not empty
n = to_process.pop()
result *= n
if n >= 3:
to_process.append(n-1)
if n >= 4:
to_process.append(n-2)
return result
create a work list (to_process)
if n >= 2, add n to the list
while to_process is not empty, pop item from list, multiply to result
if n-1 < 2, don't perform "left" operation (don't append to work list)
if n-2 < 2, don't perform "right" operation (don't append to work list)
This method has the advantage of consuming less stack. I've checked the results against recursive version for values from 1 to 25 and they were equal.
Note that it's still slow, since complexity is O(2^n) so it's beginning to be really slow from n=30 (time doubles when n increases by 1). n=28 is computed in 12 seconds on my laptop.
I've successfully used this method to fix a stack overflow problem when performing a flood fill algorithm: Fatal Python error: Cannot recover from stack overflow. During Flood Fill but here Blcknght answer is more adapted because it rethinks the way of computing it from the start.
The OP's function has the same recursive structure as the Fibonacci and Lucas functions, just with different values for f0, f1, and g:
f(0) = f0
f(1) = f1
f(n) = g(f(n-2), f(n-1), n)
This is an example of a recurrence relation. Here is an iterative version of the general solution that calculates f(n) in n steps. It corresponds to a bottom-up tail recursion.
def f(n):
if not isinstance(n, int): # Can be loosened a bit
raise TypeError('Input must be an int') # Can be more informative
if n < 0:
raise ValueError('Input must be non-negative')
if n == 0:
return f0
i, fi_1, fi = 1, f0, f1 # invariant: fi_1, fi = f(i-1), f(i)
while i < n:
i += 1
fi_1, fi = fi, g(fi_1, fi, n) # restore invariant for new i
return fi
Blckknight's answer is a simplified version of this
I'm doing the Project Euler problems, and I'm on number two. The question is:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I'm trying to solve this in python. I think I have the correct code, but for some reason When I run it with n being anything greater than or equal to 27, it will wait like a minute and just return 0. However, for anything 26 or lower, it runs fine. Here's my code:
def fib_seq(n):
if n == 0:
return n
elif n == 1:
return n
else:
return fib_seq(n-1) + fib_seq(n-2)
def get_fib_sum(n):
x = n
sum = 0
for i in range(n):
if fib_seq(x) > 4000000:
pass
elif fib_seq(x) % 2 == 0:
pass
else:
sum += fib_seq(x)
x = i
return sum
print get_fib_sum(27)
Is there anyway to fix this or at least get it to work? If it makes a difference, I'm using Wing IDE 101 Student Edition.
In your loop, you are using fib_seq(x) and it should be fib_seq(i)
Also, if you want to reduce time a bit more, you can use memoization technique
def fib_seq(n):
if n == 0:
return n
elif n == 1:
return n
else:
return fib_seq(n-1) + fib_seq(n-2)
def memoize(fn, arg):
memo = {}
if arg not in memo:
memo[arg] = fn(arg)
return memo[arg]
fibm = memoize(fib_seq,27)
print fibm
Why are you using recursion? your code is recalculating the ENTIRE fibonnaci sequence over and over and over and over and over... The code just wants the sum of the even terms. There is NO need for recursion. In pseudo-code:
t1 = 1
t2 = 2;
sum = 2;
do {
t3 = t1 + t2;
if (t3 is even) {
sum += t3;
}
t1 = t2;
t2 = t3;
} while (t2 <= 4000000)
Fibonacci sequence is often used as an example of how to write recursive code, which is ridiculous because it has a very straight-forward iterative solution:
def fib(n):
if n < 2:
return n
else:
a, b = 1, 1
for _ in range(2, n): # O(n)
a, b = b, a+b
return b
What is less obvious is that it also has a matrix representation,
F = [[0, 1]] # initial state
T = [[0, 1], # transition matrix
[1, 1]]
fib(n) = (F * T**n)[0][0]
which is extremely useful because T**n can be computed in O(log(n)) steps.
(As an aside, the eigenvector of the log of the transition matrix leads to the analytic solution,
phi = (1 + 5**0.5) / 2 # golden ratio
fib(n) = round(phi**n / 5**0.5, 0)
but that's not where I'm going with this.)
Looking at the terms produced in terms of odd-or-even, you see
n: 0, 1, 2, 3, 4, 5, 6, 7, 8, ...
f(n): 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
e/o: even, odd, odd, even, odd, odd, even, odd, odd, ...
so what you need is fib(0) + fib(3) + fib(6) + ... and computing T**3 gives you the coefficients needed to step directly from term to term.
The rest is left as an exercise for the reader ;-)
It does a lot of recursion, that's why it's taking so long.
The get_fib_sum() will evaluate fib_seq(27) in a loop, which does a lot of recursion and takes a while. Since the result of fib_seq(27) is greater then 4000000 it will then will never add anything to sum, returning 0 in the end.
def mystery_code(n):
return mystery_recursive(n, n-1)
def mystery_recursive(a, b):
if b<=0:
return 0
else:
c=mystery_recursive(a,b-1)
if a%b==0:
c+=b
return c
Could someone please help me understand what this code does?
It computes the sum of proper divisors of n.
If you step through the code you'll see it calls, e.g., mystery_recursive(5, 4) and then recursively mystery_recursive(5, 3), mystery_recursive(5, 2), mystery_recursive(5, 1), mystery_recursive(5, 0). It'll then return 0 because b <= 0.
In each of these calls, it assigns the result of a call to c and if a % b == 0 (i.e., a can be divided by b) then it adds b to c. So you'll end up with a sum of the proper divisors of n.
As already told by Simeon Visser the above code computes the sum of proper divisors of n.
if your function call is:
mystery_code(12)
then it will call the mystery recursive function (mystery_recursive(a, b)) in your code as:
mystery_recursive(12, 11)
Once the recursive function started to execute it will keep on calling itself until the condition b<=0 satisfies. In this case mystery_recursive(12, 0) will return a value of '0' to the variable 'c' to its called function mystery_recursive(12, 1). Then, beginning with the above mystery function (mystery_recursive(12, 1)) the 'c' value will be computed and returned to their respective calling functions of the same until the called function mystery_recursive(12, 11).
Output in this case: 16
Perhaps it helps to convert this recursive function to an interative version
def mystery_recursive(a, b):
c = 0
while True:
if b <= 0:
return c
if a % b == 0:
c += b
b -= 1
It's still a bit clumsy, so try to convert it to a sum generator expression
def mystery_recursive(a, b):
return sum(b for b in range(b, 0, -1) if a % b == 0)
You can even roll that back into mystery_code
def mystery_code(n):
return sum(b for b in range(n - 1, 0, -1) if n % b == 0)