TransWikia.com

Fastest and most compact way to get the smallest number that is divisible by numbers from 1 to n

Stack Overflow Asked by user13894959 on November 4, 2021

I tried my attempt at finding the smallest number that is divisible by numbers from 1 to n, and now I’m looking for advice on ways to further compact/make my solution more efficient. It would be pretty cool if there was an O(1) solution too.

def get_smallest_number(n):
    """
    returns the smallest number that is divisible by numbers from 1 to n
    """
    divisors = range(1, n+1)
    check_divisible = lambda x: all([x % y == 0 for y in divisors])
    i = 1
    while True:
        if check_divisible(i):
            return i
        i += 1

4 Answers

Another way to implement LCM

import time
from datetime import timedelta


start_time = time.monotonic()
 

def lcm(nums):
    res = 1
    for i in nums:
        res = (res * i) // gcd(res, i)
    return res
    
def gcd(a, b):
    while b:
        a, b = b, a%b
    return a
    
print(lcm([8, 9, 10, 11, 12, 13, 14, 15]))




end_time = time.monotonic()
print(f'Duration: {timedelta(seconds=end_time - start_time)}')

Produces

360360
Duration: 0:00:00.000061

[Program finished]

Answered by Subham on November 4, 2021

Start by thinking about the factorial n!. This is obviously divisible by all numbers less then n, but is not the smallest such number. For example, you could divide n! by 6, and the smaller result would still be divisible by 2 and by 3, and hence still divisible by 6.

What numbers can we divide out? Composites, like 6, don't matter as long as all the required primes are present: 2 and 3 in that case. The primes give you the composites for free. So, concentrate on the primes.

Start with 2. Look at the powers of 2: 2, 4, 8, 16, ... Run through the powers of 2 until you find the highest power that is smaller than or equal to n. That is the only power of 2 you need, all the lower powers are unnecessary. You don't need to include 4 explicitly if n is 8 or higher because then you will have 8, 16 or whatever as a multiplier. Repeat for powers of 3: 3, 9, 27, 81, ... and so on through the primes up to sqrt(n). Beyond that point you only need the remaining primes less than n, since higher powers of those primes will exceed n.

Multiply the selected prime powers together to get the least n.

Use a Sieve of Eratosthenes to generate your initial list of primes up to n.

Answered by rossum on November 4, 2021

Mathematically, you are computing the least common multiple of 1, 2, ..., n. lcm is easily derived from gcd, and lcm is an associative operation. reduce is useful for applying an associative operation to an interable. We can combine these ideas (as well as improvements due to Mark Dickinson and Eric Postpischil in the comments) to get a very fast solution:

from math import gcd
from functools import reduce

def lcm(a,b):
    return a // gcd(a,b) * b

def get_smallest_number2(n):
    return reduce(lcm,range(1 + n//2,n+1),1)

Some quick %timeit results in IPython:

%timeit get_smallest_number2(15)
2.07 µs ± 26.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit get_smallest_number(15)
443 ms ± 5.75 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

For n = 15 it is thus over 200,000 times faster. Your function fails to produce any output long before n = 100, but get_smallest_number2(100) evaluates to 69720375229712477164533808935312303556800 almost instantly.

Answered by John Coleman on November 4, 2021

The idea is to add highest divider every iteration and check from high to low. Something like this:

n = int(input("n = "))
result = 0
while True:
    result += n
    for i in range(n, 1, -1):
        if result % i != 0:
            break
    else:
        break
print(result)

Answered by Olvin Roght on November 4, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP