how can i figure the order of complexity? - python-3.x

I think I know the complexity of these 2 codes but I simply cant find the right equations to prove it.
The first one I assume is O(loglogn). The second one is O(n^2).
def f1(lst):
i=2
while i<len(lst):
print(lst[i])
i **= 2
the second code:
def f2(lst):
i = len(lst)
while i>0:
for j in range(i):
for k in range(10**5, j, -5):
print(i)
i -= 2

I think you can try to get the recursive equation first, and then use master theorem or something else to solve the recursive equations. For the first one, we use the length of the lst as the parameter.
def f1(lst1): #len(lst2)=N
i=2
while i<len(lst1):
print(lst1[i])
i **= 2
def f1(lst2): #len(lst2)=N^2
i=2
while i<len(lst2):
print(lst2[i])
i **= 2
you will notice that the second one will execute only once more than the first one. so you get
T(N^2)=T(N)+1.
For simplification, just suppose N^2=2^k,
then T(2^k)=T(2^(k/2))+1,let f(k)=T(2^k),
then f(k)=f(k/2)+1,
with the master theorem, T(N^2) = f(k) = log(k) = log(log(2^k)) = log(log(N^2)).
we get T(N) = O(loglog(N)) at last.

Related

Analaizing complexity of code (O notation)

I'm taking a cs101 course and i was asked to analize the complexity of 2 code samples in python. i was having real trouble in doing so, and especially with providing explanation. the first sample:
def f1(L):
n = len(L)
while n > 0:
n = n // 2
for i in range(n):
if i in L:
L.append(i)
return L
the second sample:
def f2(L):
n = len(L)
res = []
for i in range(500, n):
m = math.floor(math.log2(i))
for j in range(m):
k=1
while k<n:
k*=2
res.append(k)
return res
With regard to the 1st sample, in my opinion it has O(n^2) beacause the first 2 loops are like geometric series with the sum of n, and the in function in the if statement has another loop with O(n). what do you think?
And about the 2nd one, here I was thinking that the 1st for loop has O(n), the 2nd for loop has O(logn) and the while loop has O(logn) too, so in overall the O of the function is: O(n*logn^2), what is you opinion?

Number of sub sequences of length K having total sum S, given 2d array

I wish to find Number of sub sequences of length K having total sum S, given an array.
Sample Input:
a=[1,1,1,2,2] & K=2 & S=2
Sample Output:
3 {because a[0],a[1]; a[1]a[2]; a[0]a[2] are only three possible for the case}
I have tried to write a recursive loop in Python for starter but it isn't giving output as expected.Please can you help me find a loophole I might be missing on.
def rec(k, sum1, arr, i=0):
#print('k: '+str(k)+' '+'sum1: '+str(sum1)) #(1) BaseCase:
if(sum1==0 and k!=0): # Both sum(sum1) required and
return 0 # numbers from which sum is required(k)
if(k==0 and sum1 !=0): # should be simultaneously zero
return 0 # Then required subsequences are 1
if(k==0 and sum1==0 ): #
return 1 #
base_check = sum1!=0 or k!=0 #(2) if iterator i reaches final element
if(i==len(arr) and base_check): # in array we should return 0 if both k
return 0 # and sum1 aren't zero
# func rec for getting sum1 from k elements
if(sum1<arr[0]): # takes either first element or rejects it
ans=rec(k-1,sum1,arr[i+1:len(arr)],i+1) # so 2 cases in else loop
print(ans) # i is taken in as iterator to provide array
else: # input to rec func from 2nd element of array
ans=rec(k-1, sum1-arr[0], arr[i+1:len(arr)],i+1)+rec(k, sum1, arr[i+1:len(arr)],i+1)
#print('i: '+str(i)+' ans: '+str(ans))
return(ans)
a=[1,1,1,2,2]
print(rec(2,2,a))
I am still unable to process how to make changes. Once this normal recursive code is written I might go to DP approach accordinlgy.
Using itertools.combinations
Function itertools.combinations returns all the subsequences of a given lengths. Then we filter to keep only subsequences who sum up to the desired value.
import itertools
def countsubsum(a, k, s):
return sum(1 for c in itertools.combinations(a,k) if sum(c)==s)
Fixing your code
Your code looks pretty good, but there are two things that appear wrong about it.
What is this if for?
At first I was a bit confused about if(sum1<arr[0]):. I think you can (and should) always go to the else branch. After thinking about it some more, I understand you are trying to get rid of one of the two recursive calls if arr[0] is too large to be taken, which is smart, but this makes the assumption that all elements in the array are nonnegative. If the array is allowed to contain negative numbers, then you can include a large a[0] in the subsequence, and hope for a negative element to compensate. So if the array can contain negative numbers, you should get rid of this if/else and always execute the two recursive calls from the else branch.
You are slicing wrong
You maintain a variable i to remember where to start in the array; but you also slice the array. Pretty soon your indices become wrong. You should use slices, or use an index i, but not both.
# WRONG
ans=rec(k-1, sum1-arr[0], arr[i+1:len(arr)],i+1)+rec(k, sum1, arr[i+1:len(arr)],i+1)
# CORRECT
ans = rec(k-1, sum1-arr[i], arr, i+1) + rec(k, sum1, arr, i+1)
# CORRECT
ans = rec(k-1, sum1-arr[0], arr[1:]) + rec(k, sum1, arr[1:])
To understand why using both slicing and an index gives wrong results, run the following code:
def iter_array_wrong(a, i=0):
if (a):
print(i, a)
iter_array_wrong(a[i:], i+1)
def iter_array_index(a, i=0):
if i < len(a):
print(i, a)
iter_array_index(a, i+1)
def iter_array_slice(a):
if a:
print(a)
iter_array_slice(a[1:])
print('WRONG')
iter_array_wrong(list(range(10)))
print()
print('INDEX')
iter_array_index(list(range(10)))
print()
print('SLICE')
iter_array_slice(list(range(10)))
Also note that a[i:len(a)] is exactly equivalent to a[i:] and a[0:j] is equivalent to a[:j].
Clean version of the recursion
Recursively count the subsequences who use the first element of the array, and the subsequences who don't use the first element of the array, and add the two counts. To avoid explicitly slicing the array repeatedly, which is an expensive operation, we keep a variable start to remember we are only working on subarray a[start:].
def countsubsum(a, k, s, start=0):
if k == 0:
return (1 if s == 0 else 0)
elif start == len(a):
return 0
else:
using_first_element = countsubsum(a, k-1, s-a[start], start+1)
notusing_first_elem = countsubsum(a, k, s, start+1)
return using_first_element + notusing_first_elem

how can i print the right value in the code?

I'm new to python, and I'm having trouble resolving this code. I just have to print the position of the string when j equals r. But it prints nothing.
class List():
def __init__(self, l_red, l_erd, r):
self.l_red = "ABCEFGC"
self.l_erd = "DBFEGAC"
self.r = l_red[0]
def posicao(self):
j = self.l_red[0];
while self.l_erd[j] != self.r:
j = j + 1
print(j)
This is a bit hard to understand but I will give it a go.
To begin with you really need to consider using a different name for the class; List is already in python.
To instantiate and use this class you would need to use:
a_variable = List() # or whatever you are going to use
a_variable.posicao()
l_red is a string which can act like a character list, and l_erd is the same. Lists take an integer number (0, 1, 2, 3 ...) and return what was in that place. So what you need to do is something more like:
def posicao(self):
letter_of_interest = "A"
j = 0
for j in range(0, len(self.l_erd):
if letter_of_interest == self.r:
print(j)
break
Now what I have written is just for a single character, and you would use a loop to go through each character of interest, but I will leave that to you.
If you want it to find all the positions where that character exists just remove that break.
There are better methods of doing this, look into just using "ABCDE".index('A') this works.

(Python 3) Spent an hour but couldn't find the error

I am a beginner at learning python 3 and I am just writing basic programs. I wrote this simple program which would take a number in and divide it by numbers starting from 1 to the square root of the number and find the remainders and add it to a list and print it.
import math
def prime_checker(num):
n=1
list_of_remainder=[]
while n == math.floor(num**0.5):
var=int(num % n)
list_of_remainder.append(var)
n += 1
return list_of_remainder
var=prime_checker(10)
print(var)
Please tell me what I did wrong. I would like to point out here that I did try to research a bit and find error but I couldn't and only then have I posted this question.
The problem that I faced was that it printed out an empty list.
to start with, your while loop is not executed even once. The condition for your while loop is
while n == math.floor(num**0.5):
The argument num you are passing to the function prime_checker is equal to 10. In this case your condition test is:
while 1 == math.floor(10**0.5)
which is
while 1 == 3 which is obviously not true and as a result the loop is not executed even once.
import math
def prime_checker(num):
list_of_remainder = []
number=num;
n=1
x=math.floor(number**0.5)
while n <= x:
v=int(number % n)
list_of_remainder.append(v)
n += 1
return list_of_remainder
var=prime_checker(10)
print(var)

Moving average program (Python)

I'm trying to solve a math problem but I would like to make some informatic tests before to understand what happend (and maybe find the solution with my program), my problem is :
Consider the list consisting of the first n natural numbers without zero, ie from 1 to n.
We define the transformation "moving average" on the list of n elements by adding the average of all the terms at the end of the list and eliminating the first term at the beginning of the list.
For example, if n = 4, we have: (1,2,3,4) -> (2,3,4,2.5)
By iterating this process many times, one can observe a phenomenon of standardization and that all elements of the list tend to a common value when the number of iterations tends to + infinity.
It asks for the value of n for this limit is 254859658745.
Well, i'm trying to program the function "moving average" like this :
def moving_average(liste,t):
k=0
S=0
m=0
c=0
n=len(liste)
while c<t:
while k<n:
S+=int(liste[k])
k+=1
m=S/n
liste.pop(0)
liste.append(m)
c+=1
return m
My program works but don't answer what I want, if I take liste=[1,2,3] (for example) for all t>1 the answer is always the same... but I don't understand why.
Can you help me please ?
In the interests of helping you move forwards, here is the first part of an answer. The way to debug this is like this:
def moving_average(liste,t):
k=0
S=0
m=0
c=0
n=len(liste)
while c<t:
print("At c: ", c)
k=0
while k<n:
print(" At k: ", k)
S+=int(liste[k])
k+=1
m=S/n
print(" .. new S", S)
print(" .. new k", k)
print(" .. new m", m)
liste.pop(0)
liste.append(m)
print(" liste: ", liste)
c+=1
return m
test_list = [1,2,3]
test_t = 4
print("Result:", moving_average(test_list, test_t))
Then look at each result until you find one that isn't what you expect
Since you know better than I do what you expect at each step, you might find the underlying issue quicker than I can by doing this :)
Update:
One "obvious" reason why it's not working is because you're not resetting k each time around the c loop.
If you look at the output before fixing, you will see that the "at K" messages only come out once, the first time through.
I've updated the code above to fix this, and I think it does something like you are expecting. I'm not sure why you are taking taking the int() of liste[k], but that is a separate issue.

Resources