Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 12 months ago.
Improve this question
I'm doing problems from Project Euler in Ruby and implemented Atkin's sieve for finding prime numbers but it runs slower than sieve of Eratosthenes. What is the problem?
def atkin_sieve(n)
primes = [2,3,5]
sieve = Array.new(n+1, false)
y_upper = n-4 > 0 ? Math.sqrt(n-4).truncate : 1
for x in (1..Math.sqrt(n/4).truncate)
for y in (1..y_upper)
k = 4*x**2 + y**2
sieve[k] = !sieve[k] if k%12 == 1 or k%12 == 5
end
end
y_upper = n-3 > 0 ? Math.sqrt(n-3).truncate : 1
for x in (1..Math.sqrt(n/3).truncate)
for y in (1..y_upper)
k = 3*x**2 + y**2
sieve[k] = !sieve[k] if k%12 == 7
end
end
for x in (1..Math.sqrt(n).truncate)
for y in (1..x)
k = 3*x**2 - y**2
if k < n and k%12 == 11
sieve[k] = !sieve[k]
end
end
end
for j in (5...n)
if sieve[j]
prime = true
for i in (0...primes.length)
if j % (primes[i]**2) == 0
prime = false
break
end
end
primes << j if prime
end
end
primes
end
def erato_sieve(n)
primes = []
for i in (2..n)
if primes.all?{|x| i % x != 0}
primes << i
end
end
primes
end
As Wikipedia says, "The modern sieve of Atkin is more complicated, but faster when properly optimized" (my emphasis).
The first obvious place to save some time in the first set of loops would be to stop iterating over y when 4*x**2 + y**2 is greater than n. For example, if n is 1,000,000 and x is 450, then you should stop iterating when y is greater than 435 (instead of continuing to 999 as you do at the moment). So you could rewrite the first loop as:
for x in (1..Math.sqrt(n/4).truncate)
X = 4 * x ** 2
for y in (1..Math.sqrt(n - X).truncate)
k = X + y ** 2
sieve[k] = !sieve[k] if k%12 == 1 or k%12 == 5
end
end
(This also avoids re-computing 4*x**2 each time round the loop, though that is probably a very small improvement, if any.)
Similar remarks apply, of course, to the other loops over y.
A second place where you could speed things up is in the strategy for looping over y. You loop over all values of y in the range, and then check to see which ones lead to values of k with the correct remainders modulo 12. Instead, you could just loop over the right values of y only, and avoid testing the remainders altogether.
If 4*x**2 is 4 modulo 12, then y**2 must be 1 or 9 modulo 12, and so y must be 1, 3, 5, 7, or 11 modulo 12. If 4*x**2 is 8 modulo 12, then y**2 must be 5 or 9 modulo 12, so y must be 3 or 9 modulo 12. And finally, if 4*x**2 is 0 modulo 12, then y**2 must be 1 or 5 modulo 12, so y must be 1, 5, 7, 9, or 11 modulo 12.
I also note that your sieve of Eratosthenes is doing useless work by testing divisibility by all primes below i. You can halt the iteration once you've test for divisibility by all primes less than or equal to the square root of i.
It would help a lot if you actually implemented the Sieve of Eratosthenes properly in the first place.
The critical feature of that sieve is that you only do one operation per time a prime divides a number. By contrast you are doing work for every prime less than the number. The difference is subtle, but the performance implications are huge.
Here is the actual sieve that you failed to implement:
def eratosthenes_primes(n)
primes = []
could_be_prime = (0..n).map{|i| true}
could_be_prime[0] = false
could_be_prime[1] = false
i = 0
while i*i <= n
if could_be_prime[i]
j = i*i
while j <= n
could_be_prime[j] = false
j += i
end
end
i += 1
end
return (2..n).find_all{|i| could_be_prime[i]}
end
Compare this with your code for finding all of the primes up to 50,000. Also note that this can easily be sped up by a factor of 2 by special casing the logic for even numbers. With that tweak, this algorithm should be fast enough for every Project Euler problem that needs you to compute a lot of primes.
#Gareth mentions some redundant calculations regarding 4x^2+y^2. Both here and in other places where you have calculations within a loop, you can make use of calculations you've already performed and reduce this to simple addition.
Rather than X=4 * x ** 2, you could rely on the fact that X already has the value of 4 * (x-1) ** 2. Since 4x^2 = 4(x-1)^2 + 4(2x - 1), all you need to do is add 8 * x - 4 to X. You can use this same trick for k, and the other places where you have repeated calculations (like 3x^2 + y^2).
Related
Given two positive integers X and Y, find the largest permutation of X
that is less than or equal to Y. Return the largest permutation that is
less than or equal to Y as an integer. If there is no permutation of X
that is less than or equal to Y, return -1.
Example 1:
Input: X = 123, Y = 321
Output: 321
Example 2:
Input: X = 1733, Y = 3311
Output: 3173
Example 3:
Input: X = 999, Y = 111
Output: -1
Got this problem for an online assessment earlier yesterday, couldn't find an efficient solution for it and have been thinking about it but still can't think of the right approach. I first tried greedy, in which I would iterate Y from left to right and I create a permutation of X by appending the largest digit in X that is less than or equal to the digit in Y. But for X = 1733 and Y = 3311, my implementation would return -1 because the greedy algorithm rearranged X to 3317. So I turned to recursion, but as you'd expect this very quickly reached stack limit.
I've read this thread that seems to discuss a similar problem, but I believe the top solution fails for example 2. How do you approach this problem?
A recursive solution.
Sort the digits of X decreasingly. Then, as long as you find no solution
take in turn every digit in X that is not larger than the leading digit of Y;
if those digits are equal, recurse on X less this digit and the tail of Y;
if the digit of X is smaller (or X is empty), you are done;
if there is no such digit, you reached a dead-end.
This works because you are trying the permutations of X by decreasing value.
321 vs. 321
3 21 vs. 3 21
21 vs. 21
1 vs. 1
Done
7331 vs. 3311
3 731 vs. 3 311
3 71 vs. 3 11
1 7 vs. 1 1
Dead end
1 73 vs. 3 11
Done
999 vs. 111
Dead end
A non-recursive efficient solution, hinted by #Stef.
The permutations of X can be ordered increasingly by sorting the digits then picking every first digit and recursing on the remaining ones. This established a bijection between the permutations and the integers in [0, d!) for d digits.
For an integer m, you can retrieve the corresponding permutation using a conversion from the factorial basis (take the quotient by (d-1)! and proceed recursively with the remainder). This takes d operations, and you can compare the permutation to Y in O(d) operations.
Now just implement a dichotomic search on the d! permutations, which takes O(d.log(d!)) = O(d².log(d))) operations.
Update: the second solution only works for distinct digits otherwise the permutations do not yield increasing numbers. I hope that there is a workaround.
If X has more digits then there is no solution. If Y has more digits then a descending sort of the digits of X is the solution. Assuming X and Y have the same number of digits:
Put the digits of X in a counting hash.
For each digit of Y going in descending order (left-to-right), take the max digit of X that isn't greater than it and use that in your permutation.
If you ever place a digit lower than its counterpart in Y, place all remaining digits in descending order.
If there ever isn't a non-greater digit available then do the following: repeatedly unwind your prior move until you get to a digit where a lower digit was available. Select the max such lower digit. Then, all remaining digits can be placed in descending order from the map. If there is no such digit (where a lower digit could have been chosen) then there is no solution.
If you get through all the digits then you've produced the max solution.
This is linear in the number of digits if this is limited to base 10. If your base can vary, this is O(num_digits * base)
Here's Ruby code for this.
def get_perm(x, y)
# hist keeps a count of each of the digits of x
hist = Hash.new 0; x.digits.each { |d| hist[d] += 1 }
# output_digits is the answer we're building
output_digits = []
y_digits = y.digits
x_digits = x.digits
# If x has fewer digits then all permutations are good so pick the largest
if x.digits.length < y.digits.length
9.downto(0) do |digit|
output_digits += [digit] * hist[digit]
end
return output_digits
end
# If y has fewer digits then no permutation is good, return -1
if y.digits.length < x.digits.length
return -1
end
# parse the digits of y
(y_digits.length - 1).downto(0) do |i|
cur_y_digit = y_digits[i]
# use the current digit of y if possible
if hist[cur_y_digit] > 0
hist[cur_y_digit] -= 1
output_digits.append(cur_y_digit)
return output_digits if i == 0
# otherwise, use the largest smaller digit available if possible
else
(cur_y_digit - 1).downto(0) do |smaller_digit|
if hist[smaller_digit] > 0
# place the smaller digit, then all remaining digits in descending order
hist[smaller_digit] -= 1
output_digits.append(smaller_digit)
9.downto(0) do |digit|
output_digits += [digit] * hist[digit]
end
return output_digits
end
end
# If we make it here then no digit was available; we need to unwind moves until we
# can replace a digit of our solution with a smaller digit
smallest_digit = hist.keys.min
while i < (y.digits.length - 1) do
i += 1
cur_y_digit = y_digits[i]
cur_unwound_digit = output_digits.pop
hist[cur_unwound_digit] += 1
smallest_digit = [smallest_digit, cur_unwound_digit].min
if cur_y_digit > smallest_digit
(cur_y_digit - 1).downto(smallest_digit) do |d|
if hist[d] >= 1
output_digits.append(d)
hist[d] -= 1
9.downto(0) do |digit|
output_digits += [digit] * hist[digit]
end
return output_digits
end
end
end
end
return -1
end
end
end
Outputs for OP sample cases:
> get_perm(123, 321)
=> [3, 2, 1]
> get_perm(1733, 3311)
=> [3, 1, 7, 3]
> get_perm(999, 111)
=> -1
If Z is the answer, and the numbers have n digits, you can show that there is an index i such that Z[:i] = Y[:i], Z[i]<Y[i], and Z[i+1:] is as large as possible given digits of X \ Z[:i+1] (I use python array slice notation, and the last expression means "the set of digits of X minus those already chosen in Z up to i+1").
Given this, you can easily loop over each candidate i, and efficiently check if it's feasible to chose such i as in above. The solution is with the largest possible i.
The solution should be O(n*log(n)).
I'll leave the proof and implementation details, as I understand it's a homework :)
So what I want to do is breaking down numbers that are dozens of thousands big into smaller numbers, preferably 2~9.
The first thing came to my mind was prime factorization, for instance the number 49392 can be expressed as (2 x 2 x 2 x 2 x 3 x 3 x 7 x 7 x 7). But there are prime numbers and numbers such as 25378 = 2 × 12689 that cant be expressed with only multiplication.
So I want to break these numbers down using multiplication and addition, for example, the number 25378 could be expressed as 25346 + 32 = (2 × 19 × 23 × 29) + (2^5). Still, 23 and 29 are too big but I just picked random number just to show what I mean by using addtion and multiplication together to express big numbers, I'm sure there's a better combination of number that express 25378 than 25346 and 32.
Anyways, I thought programming this would involve ton of unnecessary if statement and would be incredibly slow in the big picture. So I was wondering, if there is a mathematical algorithm or function that does this thing? If not, I could just optimize the code myself, but I was just curious, I couldn't find anything on google myself though.
Assuming the problem is to write a number as the simplest expression containing the numbers 1-9, addition and multiplication (simplest = smallest number of operators), then this Python program does this in O(N^2) time.
A number N can be written as the sum or product of two smaller numbers, so if you've precalculated the simplest way of constructing the numbers 1..N-1, then you can find the simplest way of constructing N in O(N) time. Then it's just a matter of avoiding duplicate work -- for example without loss of generality in the expressions A+B and AB, A<=B, and nicely printing out the final expression.
def nice_exp(x, pri):
if isinstance(x, int):
return str(x)
else:
oppri = 1 if x[0] == '*' else 0
if oppri < pri:
bracks = '()'
else:
bracks = ['', '']
return '%s%s %s %s%s' % (bracks[0], nice_exp(x[1], oppri), x[0], nice_exp(x[2], oppri), bracks[1])
def solve(N):
infinity = 1e12
size = [infinity] * (N+1)
expr = [None] * (N+1)
for i in range(N+1):
if i < 10:
size[i] = 1
expr[i] = i
continue
for j in range(2, i):
if j * j > i: break
if i%j == 0 and size[j] + size[i//j] + 1 < size[i]:
size[i] = size[j] + size[i//j] + 1
expr[i] = ('*', expr[j], expr[i//j])
for j in range(1, i):
if j > i-j: break
if size[j] + size[i-j] + 1 < size[i]:
size[i] = size[j] + size[i-j] + 1
expr[i] = ('+', expr[j], expr[i-j])
return nice_exp(expr[N], 0)
print(solve(25378))
Output:
2 * (5 + 4 * 7 * (5 + 7 * 8 * 8))
Working on project Euler problem (26), and wanting to use an algorithm looking for the prime, p with the largest order of 10 modulo p. Essentially the problem is to look for the denominator which creates the longest repetend in a decimal. After a bunch of wikipedia reading, it looks like the prime described above would fulfill that. But, unfortunately, it looks like taking the very large powers of 10 results in an error. My question then is : is there a way of getting around this error (making the numbers smaller), or should I abandon this strategy and just do long division (with the plan being to focus on the primes).
[of note, in the order_ten method I can get it to run if I limit the powers of 10 to 300 and probably can go a bit long, which goes along with the length of a long]
import math
def prime_seive(limit):
seive_list = [True]*limit
seive_list[0] = seive_list[1] = False
for i in range(2, limit):
if seive_list[i] == True :
n = 2
while i*n < limit :
seive_list[i*n] = False #get rid of multiples
n = n+1
prime_numbers = [i for i,j in enumerate(seive_list) if j == True]
return prime_numbers
def order_ten(n) :
for k in range(1, n) :
if (math.pow(10,k) -1)%n == 0:
return k
primes = prime_seive(1000)
max_order = 0
max_order_d = -1
for x in reversed(primes) :
order = order_ten(x)
if order > max_order :
max_order = order
max_order_d = x
print max_order
print max_order_d
I suspect that the problem is that your numbers get to large when first taking a large power of ten and then computing the value mod n. (For instance If I asked you to compute 10^11 mod 11, you could remark than 10 mod 11 is (-1) and thus 10^11 mod 11 is just (-1)^11 mod 11 ie. -1.)
Maybe you could try programming your own exponentiation routine mod n, something like (in pseudo code)
myPow (int k, int n) {
if (k==0) return 1;
else return ((myPow(k-1,n)*10)%n);
}
This way you never deal with numbers larger than n.
The way it is written you will get a linear complexity in k for computing the power, and thus a quadratic complexity in n for your function order_ten(n). If this is too slow for you could improve the function myPow to use some smart exponentiation.
https://projecteuler.net/problem=35
All problems on Project Euler are supposed to be solvable by a program in under 1 minute. My solution, however, has a runtime of almost 3 minutes. Other solutions I've seen online are similar to mine conceptually, but have runtimes that are exponentially faster. Can anyone help make my code more efficient/run faster?
Thanks!
#genPrimes takes an argument n and returns a list of all prime numbers less than n
def genPrimes(n):
primeList = [2]
number = 3
while(number < n):
isPrime = True
for element in primeList:
if element > number**0.5:
break
if number%element == 0 and element <= number**0.5:
isPrime = False
break
if isPrime == True:
primeList.append(number)
number += 2
return primeList
#isCircular takes a number as input and returns True if all rotations of that number are prime
def isCircular(prime):
original = prime
isCircular = True
prime = int(str(prime)[-1] + str(prime)[:len(str(prime)) - 1])
while(prime != original):
if prime not in primeList:
isCircular = False
break
prime = int(str(prime)[-1] + str(prime)[:len(str(prime)) - 1])
return isCircular
primeList = genPrimes(1000000)
circCount = 0
for prime in primeList:
if isCircular(prime):
circCount += 1
print circCount
Two modifications of your code yield a pretty fast solution (roughly 2 seconds on my machine):
Generating primes is a common problem with many solutions on the web. I replaced yours with rwh_primes1 from this article:
def genPrimes(n):
sieve = [True] * (n/2)
for i in xrange(3,int(n**0.5)+1,2):
if sieve[i/2]:
sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
It is about 65 times faster (0.04 seconds).
The most important step I'd suggest, however, is to filter the list of generated primes. Since each circularly shifted version of an integer has to be prime, the circular prime must not contain certain digits. The prime 23, e.g., can be easily spotted as an invalid candidate, because it contains a 2, which indicates divisibility by two when this is the last digit. Thus you might remove all such bad candidates by the following simple method:
def filterPrimes(primeList):
for i in primeList[3:]:
if '0' in str(i) or '2' in str(i) or '4' in str(i) \
or '5' in str(i) or '6' in str(i) or '8' in str(i):
primeList.remove(i)
return primeList
Note that the loop starts at the fourth prime number to avoid removing the number 2 or 5.
The filtering step takes most of the computing time (about 1.9 seconds), but reduces the number of circular prime candidates dramatically from 78498 to 1113 (= 98.5 % reduction)!
The last step, the circulation of each remaining candidate, can be done as you suggested. If you wish, you can simplify the code as follows:
circCount = sum(map(isCircular, primeList))
Due to the reduced candidate set this step is completed in only 0.03 seconds.
This is a (pretty bad) solution to one of the project Euler problems. The problem was to find the 10_001st prime number. The code below does it, but it takes 8 minutes to run. Can you explain why that is the case and how to optimize it?
primes = []
number = 2.0
until primes[10000] != nil
if (2..(number - 1)).any? do |n|
number % n == 0
end == false
primes << number
end
number = number + 1.0
end
puts primes[10000]
Some simple optimizations to prime finding:
Start by pushing 2 onto your primes list, and start by checking if 3 is a prime. (This eliminates needing to write special case code for the numbers 0 to 2)
You only have to check numbers that are odd for prime candidacy. (Or, if you start by adding 2/3/5 and checking 7, you only need to check numbers that are 1 or 5 after doing % 6. Or... You get the idea)
You only have to see if your current candidate x is divisible by factors up to sqrt(x)—because any factor above sqrt(x) divides x into a number below sqrt(x), and you've already checked all of those.
You only have to check numbers in your prime list, instead of all numbers, for divisors of x - since all composite numbers are divisible by primes. For example, 81 is 9*9 - but 9*9 is 3*3*9, 9 being composite, so you'll discover it's a prime when you check it against 3. Therefore you never need to test if 9 is a factor, and so on for every composite factor.
There are very optimized, sped up prime finding functions (see the Sieve of Atkin for a start), but these are the common optimizations that are easy to come up with.
Do you really have to check if the number divides with all previous numbers? Check only with the smaller primes you already discovered. Also, why using floats where integers are perfectly fine?
EDIT:
Some possible changes (not best algorithm, can be improved):
primes = [2, 3, 5]
num = 7
until primes[10000]
is_prime = true
i = 0
sqrtnum = Math.sqrt(num).ceil
while (n=primes[i+=1]) <= sqrtnum
if num % n == 0
is_prime = false
break
end
end
if is_prime
primes << num
end
num += 2
end
puts primes[10000]
On my computer (for 1000 primes):
Yours:
real 0m3.300s
user 0m3.284s
sys 0m0.000s
Mine:
real 0m0.045s
user 0m0.040s
sys 0m0.004s