I would like it if someone could please explain to me why the following code has so much additional overhead. At 100k iterations, the speed is the same for either case (2.2 sec). When increasing to 1E6 iterations case "B" never finishes, while case "A" takes only 29 seconds.
Case "A"
while n is not 1:
foo
Case "B"
while n > 1:
foo
Complete code if of any help
def coll(n):
count = 0
# while n is not 1:
while n > 1:
count += 1
if not n % 2:
n /= 2
else:
n = 3*n + 1
return count
for x in range(1,100000):
count = coll(x)
First of all, you should use n > 1 or n != 1, not n is not 1. The fact that the latter works is an implementation detail, and obviously it's not working for you.
The reason it's not working is because there are values of x in your code that cause the Collatz sequence to go over the value of sys.maxint, which turns n into a long. Then, even when it ends up going back down to 1, it's actually 1L; a long, not an int.
Try using while n is not 1 and repr(n) != '1L':, and it'll work as you expect. But don't do that; just use n > 1 or n != 1.
Generally in Python, is is extremely fast to check, as it uses referential equality, so all that needs to be checked is that two objects have the same memory location. Note that the only reason your code works is that most implementations of Python generally maintain a pool of the smaller integers, so that every 1 always refers to the same 1, for example, where there may be multiple objects representing 1000. In those cases, n is 1000 would fail, where n == 1000 would work. Your code is relying on this integer pool, which is risky.
> involves a function call, which is fairly slow in Python: n > 1 translates to n.__gt__(1).
Related
I have the following function:
def pascal_triangle(i:int,j:int):
j = min(j, i-j + 1)
if i == 1 or j == 1:
return 1
elif j > i or j == 0 or i < 1 or j < 1:
return 0
else:
return pascal_triangle(i-1,j-1) + pascal_triangle(i-1,j)
The input value for j has the following constraint:
1<=j<=i/2
My computation for the time complexity is as follows:
f(i,j) = f(i-1,j-1) + f(i-1,j) = f(i-n,j-n) + ... + f(i-n,j)
So, to find the max n, we have:
i-n>=1
j-n>=1
i-n>=j
and, since we know that:
j>=1
j<=i/2
The max n is i/2-1, so the time complexity is O(2^(i/2-1)), and the space complexity is the maximum depth of recursion(n) times needed space for each time(O(1)), O(2^*(i/2-1)).
I hope my calculation is correct. Now my concern is that if i is odd, This number is not divisible by 2, but the terms of function must be an integer. Therefore, I want to know should I write the time complexity like this:
The time complexity and space complexity of the function are both:
O(2^(i/2-1)) if i is even
O(2^(i/2-0.5)) if i is odd
At a first glance, the time and space analysis looks (roughly) correct. I haven't made a super close inspection, however, since it doesn't appear to be the focus of the question.
Regarding the time complexity for even / odd inputs, the answer is that the time complexity is O(sqrt(2)^i), regardless of whether i is even or odd.
In the even case, we have O(2^(i / 2 - 1)) ==> O(1/2 * sqrt(2)^i) ==> O(sqrt(2)^i).
In the odd case, we have O(2^(i / 2 - 0.5)) ==> O(sqrt(2) / 2 * sqrt(2)^i) ==> O(sqrt(2)^i).
What you've written is technically correct, but significantly more verbose than necessary. (At the very least, it's poor style, and if this question was on a homework assignment or an exam, I personally think one could justify a penalty on this basis.)
I am working on this code challenge on HackerRank: Day 29: Bitwise AND:
Task
Given set 𝑆={1,2,3,...,𝑁}. Find two integers, 𝐴 and 𝐵 (where 𝐴 < 𝐵), from set 𝑆 such that the value of 𝐴&𝐵 is the
maximum possible and also less than a given integer, 𝐾. In this case,
& represents the bitwise AND operator.
Function Description
Complete the bitwiseAnd function in the editor below.
bitwiseAnd has the following parameter(s):
int N: the maximum integer to consider
int K: the limit of the result, inclusive
Returns
int: the maximum value of 𝐴&𝐵 within the limit.
Input Format
The first line contains an integer, 𝑇, the number of test cases. Each
of the 𝑇 subsequent lines defines a test case as 2 space-separated
integers, 𝑁 and 𝐾, respectively.
Constraints
1 ≤ 𝑇 ≤ 103
2 ≤ 𝑁 ≤ 103
2 ≤ 𝐾 ≤ 𝑁
Sample Input
STDIN Function
----- --------
3 T = 3
5 2 N = 5, K = 2
8 5 N = 8, K = 5
2 2 N = 2, K = 2*
Sample Output
1
4
0
*At the time of writing the original question has an error here. Corrected in this copy.
I was not able to solve it using Python, as the time limit was exceeded every time, with a message telling me to optimise my code (some test cases had like 1000 requests).
I then tried writing the same code in C#, and it worked perfectly, executing like 10 times faster, even without any effort in optimizing the code.
Is it possible to further optimise the code below, for example with some magic that I don't know about?
Code:
def bitwiseAnd(N, K):
result = 0
for x in range(1, N):
for y in range(x+1, N+1):
if result < x&y < K:
result = x&y
return result
for x in range(int(input())):
print(bitwiseAnd(*[int(x) for x in input().split(' ')]))
Your algorithm has a brute force approach, but it can be done more efficiently.
First, observe some properties of this problem:
𝐴 & 𝐵 will never be greater than 𝐴 nor than 𝐵
If we think we have a solution 𝐶, then both 𝐴 and 𝐵 should have the same 1-bits as 𝐶 has, including possibly a few more.
We want 𝐴 and 𝐵 to not be greater than needed, since they need to be not greater than 𝑁, so given the previous point, we should let 𝐴 be equal to 𝐶, and let 𝐵 just have one 1-bit more than 𝐴 (since it should be a different number).
The least possible value for 𝐵 is then to set a 1-bit at the least bit in 𝐴 that is still 0.
If this 𝐵 is still not greater than 𝑁, then we can conclude that 𝐶 is a solution.
With the above steps in mind, it makes sense to first try with the greatest 𝐶 possible, i.e. 𝐶=𝐾−1, and then reduce 𝐶 until the above routine finds a 𝐵 that is not greater than 𝑁.
Here is the code for that:
def bitwiseAnd(N, K):
for A in range(K - 1, 0, -1):
# Find the least bit that has a zero in this number A:
# Use some "magic" to get the number with just one 1-bit in that position
bit = (A + 1) & -(A + 1)
B = A + bit
if B <= N:
# We know that A & B == B here, so just return A
return A
return 0
So, I know if I
A) Let this run all night with an Upper Bound of 10,000,000
or
B) Change the range of n in increments of 500
I can get the answer to this Euler problem. But both of those feel like cheating / lazy. I've seen other solutions to this posted in C, but not in Python.
My main areas of optimization here would presumably be either/or/both some better manner of summing all integers up to a certain value, and not having Python constantly creating and dumping the list of factors for every single number it's checking. Having waited 20 minutes with an Upper Bound of one million and the program not completing, I'm not happy with the way I've implemented this.
for x in range(1,SomeUpperBound):
n = sum(range(1,x))
factorize(n)
def factorize(n):
for i in range(1,n+1):
if n > 1 and n % i == 0 and i not in factors:
factors.append(i)
if len(factors) == 500:
print(n)
print(factors)
else: factors.clear()
I'm currently learning Python on repl.it and I have a problem with one of my work.
My code is supposed to:
1.Input a given integer X
2.Find the greatest integer n where 2ⁿ is less than or equal to X.
3.Print the exponent value(n) and the result of the expression 2ⁿ.
But my code fail as the machine insert too big number like 10^8+2. The program completely failed
Here is the piece of code that I'm working on:
X = int(input())
a = X//2
while a > -1:
if (2**a) < =x:
print(a)
print(2**a)
break
else:
a -= 1
Can anyone find me another solution to this problem, or improve the bit of code I'm working on by its runtime? It works with small number(less than 10^6) but otherwise the program freeze.
Thanks in advance!
Of course, I can't refer to the "too big input" that you mention (since you didn't provide it), but as for the problem itself, it could be easier solved in the following way:
import numpy as np
a = int(np.log2(your_input))
The first issue I see is that in you code
if (2**a) < =x:
print(a)
print(2**a)
you calculate the value of 2**a twice. A good start could be to save the value of 2**a into a variable. However, since you are only doing powers of 2 you could also take a look at bitwise operations. So instead of doing a = X//2 you could also write
a= X >> 2
and instead of doing 2**a write
temp = 1 << a
When working with powers of 2 it can be significantly faster to work with bitwise operations.
I did it! (using some of your solutions of course)
This is my teachers code :
x = int(input())
n = 1
while 2 ** n <= x:
n += 1
print(n - 1, 2 ** (n - 1))
So I've got this snippet of code. And it works (It says 1 is non-prime).:
n = 1
s = 'prime'
for i in range(2, n / 2 + 1):
if n == 1 or n % i == 0:
s= 'non-' +s
break
print s
My problem is that if I change the fourth line to: if n % i == 0 or n == 1:, it doesn't work (it says 1 is prime.)
Why is that? Since I'm using or should it be that either one of them is True so the order doesn't count?
(I'm still learning about boolean so I may be making some basic mistake.)
Thanks in advance!
EDIT: Thanks for the answers; I never realized my issue with the range() function. And about the code working and not working: I have no idea what happened. I may have made some mistake somewhere along the way (maybe forgot to save before running the script. Although I could've sworn that it worked differently :P ). Maybe I'm just getting tired...
Thanks for the answers anyways!
In both cases, the body of the loop does not run, because when 'n' is 1, it does not fall within the range of (n,n/2+1)
The code you posted says that 1 is prime (again, because the loop body does not execute at all)
The precedence is fine. % is evaluated first, then ==, then or, so it breaks down into:
___or___
/ \
== ==
/ \ / \
n 1 % 0
/ \
n i
Your problem is that your for loop is not being executed at all, so that s is still set to "prime".
The range 2,n/2+1 when n is 1 equates to 2,1 which will result in the body not being executed.
In fact it won't be executed where n is 2 either since 2/2+1 is 2 and the range 2,2 doesn't execute. The values are the start and terminating value, not start and end (last) value - it's just fortuitous there that 2 is considered a prime by virtue of the initialisation of s :-)
Try this instead:
#!usr/bin/python
n = 9
s = 'prime'
if n == 1:
s = 'non-prime'
else:
i = 2
while i * i <= n:
if n % i == 0:
s= 'non-prime'
break
i = i + 1
print s
It's wasteful going all the way up to n/2, the square root of n is all that's needed.
i think the problem is when n is 1, the loop is skipped.
Other answers already correctly addressed your specific problem (which, in other words, is that the loop executes only if n/2 + 1 > 2, that is, n/2 > 1, which means n > 2 with new-style division [[python 3 or suitable imports from the future or flags...]], n > 3 with classic style truncating division).
Wrt the specific question you posed:
Since I'm using or should it be that
either one of them is True so the
order doesn't count?
The order does count because or (like and) is a short-circuiting operator: specifically, or is guaranteed to go left to right, and stop if the left operand is true (because it does not need to know about the right one). This doesn't matter for your specific code, but it's crucial in cases such as, e.g.:
if i == 0 or n / i > 3: ...
If or wasn't going left-to-right (and stopping ASAP), the right-hand operand might get executed even when i equals 0 -- but then the division would raise an exception! With Python's rules, this code snippet won't raise exceptions (if i is an int, at least;-).
Again: this has nothing to do with the specific problem you're having (see other answers and the start of this one), but it's important for you to know for the future, so, since you asked, I took the opportunity to explain!-)
for n in range(101):
s = 'prime'
if n < 2 or not (n & 1): ## not(n & 1) == is even number (last bit 0) == not (n % 2)
s = 'non-'+s
else:
for i in range(3, int(n**0.5) + 1,2):
if not(n % i):
s= 'non-' +s
break
print "%i is %s" % (n,s)
You need not check all even numbers and you can stop the check at square root of n.