Need help finding Big Oh, c, and No - python

Need help with these two examples. As I kind of understand Big Oh, but not really the c and No concepts. First one seems pretty straight forward. I'm pretty sure the Big Oh would be O(n^3) but I'm not sure.
f(x) = 2n3 + 5n + 2
The next one is the one that really makes me feel like idk what I'm doing.
def analyze(alist):
1 exchanges = True
2 passnum = len(alist)-1
3 while passnum > 0 and exchanges:
4 exchanges = False
5 for i in range(passnum):
6 if alist[i]>alist[i+1]:
7 exchanges = True
8 alist[i],alist[i+1]=alist[i+1],alist[i]
9 passnum = passnum-1
HE wants me to label each line regarding Big Oh (what?), and then calculate the Big Oh, c, and No.
Any help/explanation would be a huge help, I'm feeling lost. THought I had it, but its clear that I do not. Thanks

Each line represents either an elementary operation or a function.
An elementary operation is often considered to take O(1) time (constant time).
if i had this simple code and i'm looking the big Oh relative to N, a number given in argument
a = 1 // O(1) assignement is constant
b = a + 2 // O(1) addition is constant
for (a=0 to N-1) // a will take value between [0..n-1], which is n different values
a = a + 1 // addition is O(1)
//resume: i have => O(1) + O(1) + N * O(1) => O(N)
Here you see i did label each line, and i can conclude , this code is O(N) cause it's the dominant factor. You need to try to do the same for your snippet of code.

Related

How to find the numbers that their sum equal to a given number?

This seems like a repost but it's not. Most people asked for the pair numbers. I need all numbers, not just two. Like n0+n1+n2+n3+n4+...+n100=x And also, each number must be lower than the number comes before him. For example for 8 output must be:
There are 5:
7+1
5+3
6+2
5+2+1
4+3+1
In here you can see 5>3 and 6>2 and vice versa.
I came so close with this code. I found this on stackoverflow, and then improved it to according to my needs. However I tested it on a super computer, that if you give 200 to this, it says it's wrong. I just don't get it how could this be wrong? Please can someone help me improve this? With my pc it takes a lot of time. Give this 50, and it will still take hours. Here is my code:
from itertools import combinations
def solution(N):
array=[]
counter=0
for i in range(N):
if(i==0):
continue
array.append(i)
for K in range(N):
for comb in combinations(array, K):
if sum(comb) == N:
counter+=1
#print(comb) uncomment this if you like, it prints pairs.
return counter
res=solution(50)
print(res)
By the way, can I do it without itertools at all? Maybe it causes problems.
I think I may have found a solution, I will share it and maybe you can check with me if it is correct :) I assumed that all numbers must be smaller than N.
To start, I am not so sure your code is necessarily wrong. I think it produces the right answers but maybe you should consider what is happening and why your code takes so long. Currently, you are checking for all combination of sums, but by iterating in another way you can exclude many possibilities. For example, suppose my goal is to find all sums that result in a total of 8.
Suppose I now have a sum of 6 + 5 = 11. Currently, you are still checking all other possibilities when adding other numbers (i.e. 6 + 5 + 4 and 6 + 5 + 3 etc etc), but we already know they all will be >8, hence we do not even have to compute them.
As a solution we can start with the highest number smaller than our goal, i.e. 7 in our example. Then we will try all combinations with numbers smaller than this. As soon as our sum gets bigger than 8, we do not follow the trail further. This sounds a lot like recursing, which is how I currently implemented it.
To get an idea (I hope it is correct, I haven't tested it extensively):
def solution(goal, total_solutions=0, current_sum=0.0, current_value=None):
if current_value is None:
current_value = goal
# Base condition
if current_sum >= goal:
if current_sum == goal:
return total_solutions + 1
return total_solutions
for new_value in range(current_value - 1, 0, -1):
total_solutions = solution(
goal, total_solutions, current_sum + new_value, new_value
)
return total_solutions
res = solution(8)
print(res) # prints 5
So as an answer to your question, yes you can do it with itertools, but it will take a long time because you will be checking a lot of sums of which you do not really need to check.
I compared this program with yours and it produces the same output up until N=30. But then your code really starts to blow up so I won't check further.
The Answer you're looking for is in the post : programming challenge: how does this algorithm (tied to Number Theory) work?
The classical method start taking some time at the 100th step but the use of memoization also called dynamic programming reduces the complexity drastically and allows your algorithm to compute at the 4000th step without taking any time at all.

How to write a while loop in python

I am really having trouble getting started on this assignment and would really appreciate some help as a newbie!
We need to write a program called PiApproximator that approximates the mathematical constant π by summing a finite number of terms in a series for it.
The series we are using is pi=4-4/3+4/5-4/7 etc..
Since you said you just want to get started on solving this I'll break down the components of the question
While function statement; the loop needs to continue as long as the added term is greater than 1e-6, so you'll need a variable for whatever variable is added for that loop.
You need a counter for the number of loops; both for an output and in order to control whether the term will be added or subtracted from the total (hint: a % is useful here)
You will need a way to change the next number in the series; a good way of doing this would be to link it to the loop counter ie series_num = 4/(3 + 2 * loop)
I've tried to give as much info as possible without straight out giving you the answer but let me know if you need any more help
Your code has the right ideas. One solution would be to make the different parts simpler
# pi ~ + 4/1 - 4/3 + 4/5 - 4/7 ...
pi, x, d = 0, 1, 1
while 4 / d > 1e-6:
pi += 4 / d * x
d += 2
x *= -1
print(f'Approximation of pi is {pi} [in {(d+1) // 2} iterations]')
Output
Approximation of pi is 3.141592153589724 [in 2000001 iterations]

Big O with 2 variables which multiply together

If I take the function:
def nested_multiplier(a, b):
"""
returns a*b
"""
count = 0
for i in range(a):
for j in range(b):
count += 1
return count
It is fairly clear here that the complexity in terms of number of asignments is going to be a * b.
Fine so far so good.
So if I want to work out the Big O in terms of a I guess I have to consider that the function has O(n) because I must consider b as a constant value in this case?
And equally if I want the big O in terms of b it would be O(n) for the same reasons.
This seems to make sense but intuitively with a nested iteration block like this I expect an O(n^2), or some other exponential type value. And this makes perfect sense when you consider a and b in terms of having the same value (i.e. let a = 5 and let b = 5 there will be 25 assignments).
So what is the correct way to express the complexity of this function in Big O notation?
You can use two variables inside the O(n) notation. For example this graph complexity question uses both the number of vertices and edges for complexity analysis. In your case the answer will be O(a*b), or if you want it more n-like, you can use O(n*m).
Assuming b or a as a constant to use only one variable in O(n) notation is misleading for analysis. Always use every input that affects complexity.
Big O is a function of how you measure input size. If you measure it as e.g. n = |a| + |b| or n = max(|a|,|b|) then the complexity is O(n^2), which is the most reasonable way to express it in terms of a single parameter. On the other hand, you could simply leave it as O(a*b). Saying that it is O(a) or O(b) is misleading unless you intend to fix one or the other of the values.
Well, essentially it's exactly as you've said it yourself:
If one of your parameters a or b is going to be a constant then the time complexity is going to be O(b) or O(a), because it doesn't depend on the constant factor.
If however, both a and b can be arbitrarily big then the asypmtotic time complexity (a -> inf and b -> inf) will be O(a * b).
The essential point is that Big O notation describes asymptotic complexities, so while it can be a little confusing thinking about the runtime for small a and b intuitively for when one of them is a constant, when you let the other value grow towards infinity, the linear runtimes make sense again.

Filtering out conditioned arrays from a matrix

In Sweden there is a football (soccer) betting game where you try to find the outcome of 13 matches. Since each match can have a home win, a draw or an away team win this leads to 3**13=1594323 possible outcomes. You win if you have 10 to 13 matches correct. You don't want this to occur when a lot of other people also have high scores since the prize sum is divided among all winners. This is the background to the more generic question that I'm looking for an answer to: how to find all arrays that differ by at least x elements from a given array within the matrix (in this case 1594323*13).
The first obvious idea that came to my mind was to have 13 nested for loops and compare one array at the time. However, I'm using this problem as a training session to learn myself Python programming. Python is not the optimal tool for this kind of task and I could turn to C to get a faster program but I'm interested in the best algorithm as such.
In Python I tried the nested for loop method up to 10 matches, then the execution time got too long, 5 seconds on the netbook I'm using. For each added match, the execution time went up tenfold.
Another approach would be to use a database and that might be the solution but I'm curious what the fastest way of solving this kind of problem is. I haven't been successful googling this problem, maybe because it's hard to use the correct description of the problem in a short search.
Here's a recursive solution that terminates in about 5 seconds on my machine, when given an x value of 0 (the worst case). For x values of 10 and above it's nearly instantaneous.
def arrays_with_differences(arr, x):
if x > len(arr):
return []
if len(arr) == 0:
return [[]]
smallColl1 = arrays_with_differences(arr[:len(arr)-1], x)
smallColl2 = arrays_with_differences(arr[:len(arr)-1], x-1)
last = arr[len(arr)-1]
altLast1 = (last + 1) % 3
altLast2 = (last + 2) % 3
result = [smallArr + [last] for smallArr in smallColl1]
result.extend([smallArr + [altLast1] for smallArr in smallColl2])
result.extend([smallArr + [altLast2] for smallArr in smallColl2])
return result
result = arrays_with_differences([1,0,1,0,1,1,1,1,1,1,1,1,1], 4)
print(len(result))

Writing a double sum in Python

I am new to StackOverflow, and I am extremely new to Python.
My problem is this... I am needing to write a double-sum, as follows:
The motivation is that this is the angular correction to the gravitational potential used for the geoid.
I am having difficulty writing the sums. And please, before you say "Go to such-and-such a resource," or get impatient with me, this is the first time I have ever done coding/programming/whatever this is.
Is this a good place to use a "for" loop?
I have data for the two indices (n,m) and for the coefficients c_{nm} and s_{nm} in a .txt file. Each of those items is a column. When I say usecols, do I number them 0 through 3, or 1 through 4?
(the equation above)
\begin{equation}
V(r, \phi, \lambda) = \sum_{n=2}^{360}\left(\frac{a}{r}\right)^{n}\sum_{m=0}^{n}\left[c_{nm}*\cos{(m\lambda)} + s_{nm}*\sin{(m\lambda)}\right]*\sqrt{\frac{(n-m)!}{(n+m)!}(2n + 1)(2 - \delta_{m0})}P_{nm}(\sin{\lambda})
\end{equation}
(2) Yes, a "for" loop is fine. As #jpmc26 notes, a generator expression is a good alternative to a "for" loop. IMO, you'll want to use numpy if efficiency is important to you.
(3) As #askewchan notes, "usecols" refers to an argument of genfromtxt; as specified in that documentation, column indexes start at 0, so you'll want to use 0 to 3.
A naive implementation might be okay since the larger factorial is the denominator, but I wouldn't be surprised if you run into numerical issues. Here's something to get you started. Note that you'll need to define P() and a. I don't understand how "0 through 3" relates to c and s since their indexes range much further. I'm going to assume that each (and delta) has its own file of values.
import math
import numpy
c = numpy.getfromtxt("the_c_file.txt")
s = numpy.getfromtxt("the_s_file.txt")
delta = numpy.getfromtxt("the_delta_file.txt")
def V(r, phi, lam):
ret = 0
for n in xrange(2, 361):
for m in xrange(0, n + 1):
inner = c[n,m]*math.cos(m*lam) + s[n,m]*math.sin(m*lam)
inner *= math.sqrt(math.factorial(n-m)/math.factorial(n+m)*(2*n+1)*(2-delta[m,0]))
inner *= P(n, m, math.sin(lam))
ret += math.pow(a/r, n) * inner
return ret
Make sure to write unittests to check the math. Note that "lambda" is a reserved word.

Categories