简体   繁体   中英

Smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

What is wrong with my code? When i run the program nothing is printed. I want to print the smallest number that is evenly divisible by all of the numbers from 1 to 20.

found = False
i = 20
while found==False:
    c = 0    # c checks if the number is the one im looking for
    for x in range(1,21):
        if i%x==0:
            c = c + 1
    if c==20: # if c = 20 then its the number im looking for
        print i
        found = True
    i = i + 1    

Brute forcing this is WAY too slow. You need to find out what the prime factors of each number below 20 are, and then construct the smallest number that includes the same, and it will be the answer.

from collections import Counter

primes_below_20 = [2, 3, 5, 7, 11, 13, 17, 19]

def prime_factors(n):
    # Assume n <= 20 
    if n == 1:
        return []
    for prime in primes_below_20:
        if n % prime == 0:
            return [prime] + prime_factors(n / prime)

 primes_needed = Counter()

 for n in range(2, 21):
     primes = Counter(prime_factors(n))
     primes_needed = primes_needed | primes  # | gives the max of existing values

 total = 1
 for prime, amount in primes_needed.items():
     total *= prime ** amount

 print total

Brute force:

from itertools import count
for i in count(20):
    if all(map(lambda x: i % x == 0, range(1, 21))):
        print i
        break

Non-brute-force:

from itertools import count, takewhile

def primes(n):
    "Generate prime numbers up to n"
    seen = list()
    for i in xrange(2, n + 1):
        if all(map(lambda prime: i % prime, seen)):
            seen.append(i)
            yield i

def smallest(n):
    result = 1
    for prime in primes(n):
        bprime = max(takewhile(lambda x:x<=n, (prime ** c for c in count(1))))
        # we could just take last instead of max()
        result *= bprime
    return result

print smallest(20)
def is_divisible(n):
    for divisor in range(2, 21):
         if n % divisor != 0:
              return False
         return True


number = 1
while not is_divisible(number):
     number+=1
print(number)

However, you don't have to check all numbers 1..20. If a number is divisible by 20, it is divisible by 2, 5, 10. Extending this, it would be sufficient to check only divisors from 11..20. Another simple thing would be to increase the candidate solutions by 20 ( number += 20 ) instead of 1, since any other number would not be divisible by 20.

however, you are essentially looking for the least common multiple of the numbers from 1 to 20, and this can be done using prime factorization: You write each number in [1, 20] as multiple of primes, you take the largest exponential for each prime and then you multiply the results (try it manually to understand it). In this way, the number you are looking for is 2^4 *3^2 * 5 * 7 * 11 * 13 * 17 * 19

My take (though I love @ondra solution for its elegancy):

from collections import Counter, defaultdict

def primes(n):
    return list(x for x in range(1,n+1) 
        if all(x%y for y in range(2,x)))

primes_20 = primes(20)

def prime_factors(n):
    if n <= 0 or n < 20:
        raise ValueError
    factors = []
    while n > 1:
        for x in primes_20[1:]:
            if not n % x:
                n = n / x
                factors.append(x)
                break
    return factors

max_count = defaultdict(int)

for i in range(2,21):
    factors = prime_factors(i)
    counts = Counter(factors)
    for factor in counts:
        max_count[factor] = max(max_count[factor], counts[factor])

total = 1
for factor, count in max_count.items():
    total *= factor**count

assert any(total%x for x in range(2)) == False
print total

Another clean and quick thing in Ruby

def compute_lowest_dividing_number number
  for i in 2..(number/2)
    return i if number%i == 0
  end
  number
end

lcm = 1
n = 20
for i in 1..n
  # look ahead appraoch
  next_number = [i+1, n].min
  lcm *= compute_lowest_dividing_number(next_number) if lcm % next_number != 0
end
puts lcm

I tried this method and it was more easier to understand

i=1 
while True:
    if i%11==0 and i%12==0 and i%13==0 and i%14==0 and i%15==0 and i%16==0 and i%17==0 and i%18==0 and i%19==0 and i%20==0:
        break
    else:
        i+=1
print(i)

But this can be done in milliseconds by finding the prime factors from 11 to 20 and multiplying them.

So it is Euler's problem #5. I've got that one:

#making loop for range of numbers
def rangeCount(number):
    lst = [] #using lists to see divisions
    for x in range(1, 21):
        svalue = number % x
        if svalue == 0:
            lst.append(x)
    else:
        break #Need to break to minimize computation.
return lst

number = 2520 #is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder. Minimazing compute
lstpst = [] #list pasted/returned from function
while len(lstpst) < 20:
    lstpst = rangeCount(number)
    print(f"With {number} we get {lstpst}")
    number += 2 #even number must be the answer to the problem. Minimazing compute.

And it is my first post/comment on StackOverflow.

if you think carefully the answer is LCM of the numbers from 1 to n. here is the code in C++.

#include <bits/stdc++.h>
#define IOS                         \
  ios_base::sync_with_stdio(false); \
  cin.tie(NULL);

#define ll long long int

using namespace std;

ll lcm(int n) {
  ll ans = 1;
  for (ll i = 1; i <= n; i++)
    ans = (ans * i) / (__gcd(ans, i));
  return ans;
}

int main() {
  int i;
  cin >> i;
  
  cout << lcm(i);
  
  return 0;
}

Simplest Solution using Python:

num = 21

while True:
    div = 2

    while num%div == 0 and div!=21:
        div+=1

    if div == 21:
        print(num)
        break

    num+=1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM