Calculate number of function calls for any size N - python

I'm trying to understand a way to write how many times the print statement for fun1 will be called for any size N. Written in summation form. This is more of an analysis question. I know I could just setup a count variable and print the result. S is an array of N items. N is the size.
def myAlg(S,n):
for i in range(1,n+1):
for j in range(1,i+1):
for k in range(1,j+1):
if j > k:
print('fun1 called, and count is now', count)
else:
print('fun2 called')
Im honestly a little lost on how to approach this. Any explanation would be greatly appreciated.

For two first loops we have sum of arithmetic progression 1+2+3+...+n, and result is
T(n) = n*(n+1)/2
known as trianglular numbers (1,3,6,10,15,21...)
So loop for k is executed T(n) times, and inner part is executed
Q(n) = sum(T(i),i=1..n) = n*(n+1)*(n+2)/6
times, sequence is known as tetrahedral numbers (1,4,10,20,35,56...)
But we have to subtract T(n) to exclude fun2 calls (one per loop)
Result = n*(n+1)*(n+2)/6 - n*(n+1)/2 = (n-1)*n*(n+1)/6
This is the same Q sequence without the last term, so
Result(n) = Q(n-1) = (n-1)*n*(n+1)/6

Related

How to find the time complexity of this function?

def f1(n):
cnt = 0
for i in range(n):
for j in range(n):
k = 1
while k < i*j:
k *= 2
cnt += 1
return cnt
I am trying to analyze the time complexity of this function f1, I'm having some troubles dealing with the k < i*j in the loop.
My point of view:
I'm trying to find the number of iterations of the inner loop, so what I'm basically trying to find is when 2^k >= i*j, but I'm having trouble dealing in how to compute i*j each time and find the overall time complexity. I know that at the end I will have 2^k >= n^2 which gives me k >= log(n) , but I must be missing all the iterations before this and I would be happy to know how to calculate them. Any help is really appreciated, Thanks in advance!
EDIT:
With Prune's help I reached this: We're trying to calculate how many times the inner loop iterates, which is log(i*j).
taking i=2 we get log(2) + log(j) (n times) which is n + log(1)+log(2)+...+log(n).
So we have n+log(n!) for each i=0,1,...,n basically n(n+log(n!)). Which is either O(n^2) or O(nlog(n!)). as it's my first time meeting log(n!) I'm not sure which is considered to be the time complexity.
For convenience, let m = i*j.
As you've noted, you execute the while loop log(m) times.
The complexity figure you're missing is the summation:
sum([log(i*j)
for j in range(n)
for i in range(n)])
Would it help to attack this with actual numbers? For instance, try one iteration of the outer loop, with i=2. Also, we'll simplify the log expression:
sum([log(2) + log(j) for j in range(n)])
Using base 2 logs for convenience, and separating this, we have
n*1 + sum([log(j) for j in range(n)])
That's your start. Now, you need to find a closed form for sum(log(j)), and then sum that for i = 0,n
Can you take it from there?
After OP update
The desired closed form for sum(log(j)) is, indeed, log(n!)
This isn't simply "go n times`: it's the sum of log(i)*n + log(n!) over the range.

How to calculate Time Complexity of this algorithm

I am new to the concept of asymptotic analysis. I am reading "Data Structures and Algorithms in Python" by Goodrich. In that book it has an implementation as follows:
def prefix average2(S):
”””Return list such that, for all j, A[j] equals average of S[0], ..., S[j].”””
n = len(S)
A = [0] n # create new list of n zeros
for j in range(n):
A[j] = sum(S[0:j+1]) / (j+1) # record the average
return A
The book says that this code runs in O(n^2) but I don't see how. S[0:j+1] runs in O(j+1) time but how do we know what time the 'sum()' runs in and how do we get the running time to be O(n^2)?
You iterate n times in the loop. In the first iteration, you sum 1 number (1 time step), then 2 (2 time steps), and so on, until you reach n (n time steps in this iteration, you have to visit each element once). Therefore, you have 1+2+...+(n-1)+n=(n*(n+1))/2 time steps. This is equal to (n^2+n)/2, or n^2+n after eliminating constants. The order of this term is 2, therefore your running time is O(n^2) (always take the highest power).
for j in range(n): # This loop runs n times.
A[j] = sum(S[0:j+1]) # now lets extend this sum function's implementation.
I'm not sure about the implementation of sum(iterable) function but it must be something like this.
def sum(iterable):
result=0
for item in iterable: # worse time complexity: n
result+=item
return result
so, finally, your prefix_average2 function will run n*n=n^2 time in worse case (When j+1=n)
First of all, I am not an expert on this topic, but I would like to share my opinion with you.
If the code is similar to the below:
for j in range(n):
A[j] += 5
Then we can say the complexity is O(n)
You may ask why did we skip the n=len(S), and A=[0]?
Because those variables take 0(1) time to complete the action.
If we return our case:
for j in range(n):
A[j] = sum(S[0:j+1]) ....
Here, sum(S[0:j+1]) there is also a loop of summation is calculated.
You can think this as:
for q in S:
S[q] += q # This is partially right
The important thing is two-for loop calculation is handling in that code.
for j in range(n):
for q in range(S)
A[j] = ....
Therefore, the complexity is O(n^2)
The For Loop (for j in range(n)) has n iterations:
Iteration(Operation)
1st iteration( 1 operation for summing first 1 element)
2nd iteration( 2 operations for summing first 2 elements)
3rd iteration( 3 operations for summing first 3 elements)
.
.
.
(n-1)th iteration( n-1 operations for summing first n-1 elements)
nth iteration( n operations for summing first n elements)
So, the total number of operation is the summation of (1 + 2 + 3 +......(n-1) + n)...
which is (n*(n+1))//2.
So the time complexity is O(n^2) as we have to (n(n+1))//2 operations.*

python project euler 6 with any number

I'm having trouble with Project Euler #6. The question is as follows:
Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.
I'm trying to write my code in such a way that what is being asked in Euler(all numbers up to and including 100) can be substituted for any number you like (all numbers up to and including x). I decided that in order to do this, you would need 3 functions. Code is:
#the sumSquare function squares every number from 0 to number called
#in the function and adds each term to a list. the function returns the sum
#of all numbers in this list
def sumSquare(num):
list1 = []
for i in range(num+1):
x = i^2
list1.append(x)
return sum(list1)
#the squareSum function adds every whole number from 0 up to and including
#the number called in the function to list2. It returns the sum squared of #every number in the list
def squareSum(num):
list2 = []
for i in range(1,num+1):
list2.append(i)
return (sum(list2) * sum(list2))
def ans(num):
return squareSum(num) - sumSquare(num)
print ans(100)
My output is 2549748 but I'm reading online that the correct solution is 25164150. Does anyone see where I am going wrong. I am just learning to code so I may be missing something that would be easy to spot by someone more experienced. But as far as I can tell, the lists are being filled with what would be the appropriate numbers before they are summed.
This
i^2
Is not a square in Python. Use i*i or i**2 for a square.
Your code is anylanguage code. But with sintax error.
Really power in Python is **
So.
Python-style code looks like that one:
print(sum(range(1, 101))**2 - sum([i**2 for i in range(1, 101)]))
Thats why they love the Python (R)
Thanks to everyone for the input. After thinking a bit more I realized just how overly convoluted this code was. I realized that if all three functions are taking the same variable to solve the problem, it can be simplified into one function that takes care of each step on its own. Came up with this solution which is obviously much more efficient:
import time
def ans(num):
numSq = []
for i in range(1, num+1):
numSq.append(i**2)
return ((sum(range(1, num+1))**2)-sum(numSq))
start_time = time.time()
print ans(100)
print "This program took {} seconds to execute.".\
format(time.time() - start_time)
Running the program you get:
25164150
This program took 0.00800013542175 seconds to execute.
Again, thanks for the input on my first post!
def diffSum():
sumSquares = 0
squareSum = 0
sumT = 0
for i in range(1,101):
sumSquares = sumSquares + (i * i)
for i in range(1,101):
sumT = sumT + i
squareSum = sumT * sumT
return squareSum - sumSquares
#sumsquares gets all the summation of the square numbers of the first 100 numbers
#sumT stores the summation of the first 100 numbers
#squareSum squares the summation of the first 100 numbers
#returns the difference between sumSquares and squareSum

What would be the best answer for this Fibonacci excercise in Python?

What's the best answer for this Fibonacci exercise in Python?
http://www.scipy-lectures.org/intro/language/functions.html#exercises
Exercise: Fibonacci sequence
Write a function that displays the n first terms of the Fibonacci
sequence, defined by:
u0 = 1; u1 = 1
u(n+2) = u(n+1) + un
If this were simply asking a Fibonacci code, I would write like this:
def fibo_R(n):
if n == 1 or n == 2:
return 1
return fibo_R(n-1) + fibo_R(n-2)
print(fibo_R(6))
... However, in this exercise, the initial conditions are both 1 and 1, and the calculation is going towards the positive direction (+). I don't know how to set the end condition. I've searched for an answer, but I couldn't find any. How would you answer this?
Note that u_(n+2) = u_(n+1) + u_n is equivalent to u_n = u_(n-1) + u_(n-2), i.e. your previous code will still apply. Fibonacci numbers are by definition defined in terms of their predecessors, no matter how you phrase the problem.
A good approach to solve this is to define a generator which produces the elements of the Fibonacci sequence on demand:
def fibonacci():
i = 1
j = 1
while True:
yield i
x = i + j
i = j
j = x
You can then take the first N items of the generator via e.g. itertools.islice, or you use enumerate to keep track of how many numbers you saw:
for i, x in enumerate(fibonacci()):
if i > n:
break
print x
Having a generator means that you can use the same code for solving many different problems (and quite efficiently though), such as:
getting the n'th fibonacci number
getting the first n fibonacci numbers
getting all fibonacci numbers satisfying some predicate (e.g. all fibonacci numbers lower than 100)
The best way to calculate a fibonacci sequence is by simply starting at the beginning and looping until you have calculated the n-th number. Recursion produces way too many method calls since you are calculating the same numbers over and over again.
This function calculates the first n fibonacci numbers, stores them in a list and then prints them out:
def fibonacci(n):
array = [1]
a = 1
b = 1
if n == 1:
print array
for i in range(n-1):
fib = a + b
a = b
b = fib
array.append(fib)
print array
If you want a super memory-efficient solution, use a generator that only produces the next number on demand:
def fib_generator():
e1, e2 = 0, 1
while True:
e1,e2 = e2, e1+e2
yield e1
f = fib_generator()
print(next(f))
print(next(f))
print(next(f))
## dump the rest with a for-loop
for i in range(3, 50):
print(next(f))
The recursive solution is the most elegant, but it is slow. Keiwan's loop is the fastest for a large number of elements.
Yes, definitely no globals as correctly observed by DSM. Thanks!
An alternative recursive just to show that things can be done in slightly different ways:
def fib2(n): return n if n < 2 else fib2( n - 1 ) + fib2( n - 2 )

Fibonacci and Prime numbers Python

Let F[n] and P[n] be the nth Fibonacci and prime number respectively. There are some values of n for which F[n] % P[n] = 0.
Let the first k indices which satisfies this condition be n_1 < n_2 < ... < n_k.
I want to calculate the sum of the first k indices (i.e. n_1 + ... + n_k). The program is fine for k = 2 but too slow for k = 5 (as below).
Is there any way I can speed this up?
def primelist(n):
prime = [True]*n
for p in range(3,n,2):
if p**2>n:
break
if prime[p]:
for i in range(p*p,n,2*p):
prime[i]=False
return [2]+[p for p in range(3,n,2) if prime[p]]
l= primelist(100000)
l.insert(0,0)
fib = [0,1]
for i in range(2,len(l)):
fib.append(fib[i-1]+fib[i-2])
k=0
sum_=0
i=1
while i<len(l):
if fib[i]%l[i]==0:
k=k+1
sum_=sum_+i
if k==5:
i=len(l)-1
i=i+1
print sum_
Both of those series are calculation intensive, in other words it doesn't surprise me that it is taking so much time to calculate the values especially that python is an interpreted language, making it slower in these kinds of calculations. I would suggest you use the library numpy to do the calculations you need. It will make your calculations much faster.
First of all, you should redefine your variables like;
i+=1
Not;
i=i+1
Second one, tuples process are faster than lists. So you could use tuples instead of lists if you are not going to change anything.
Also in this statement;
for p in range(3,n,2):
if p**2>n:
break
You probably want to do if p bigger than square root of n.So you should change that line to;
for p in range (3,int(n**0.5+1),2):

Categories

Resources