math
combinatorics
least common multiple
subsets
number theory

Find the sum of least common multiples of all subsets of a given set

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

This problem combines two expensive operations: enumerating subsets and computing least common multiples. The direct solution is simple and often good enough for small input sizes, but it helps to be explicit about the subset convention and where the time goes.

Define the Problem Precisely

Given a list of positive integers, compute the LCM of every subset and add those values together. The first decision is whether the empty subset contributes to the sum.

Both conventions appear in practice:

  • include the empty subset and assign it value 1
  • exclude the empty subset entirely

Neither is universally correct, so state the rule in code. Once that choice is fixed, the algorithm is straightforward.

For a small example, consider 2, 3, 4.

  • 'lcm(2) = 2'
  • 'lcm(3) = 3'
  • 'lcm(4) = 4'
  • 'lcm(2, 3) = 6'
  • 'lcm(2, 4) = 4'
  • 'lcm(3, 4) = 12'
  • 'lcm(2, 3, 4) = 12'

If you exclude the empty subset, the total is 43. If you include it as 1, the total becomes 44.

A Direct Python Solution

Python already gives you the tools you need for a clean implementation. The function below is runnable and makes the empty-subset choice explicit:

python
1from itertools import combinations
2from math import lcm
3
4
5def sum_of_subset_lcms(values, include_empty=False):
6    total = 1 if include_empty else 0
7
8    for size in range(1, len(values) + 1):
9        for subset in combinations(values, size):
10            current = 1
11            for value in subset:
12                current = lcm(current, value)
13            total += current
14
15    return total
16
17
18numbers = [2, 3, 4]
19print(sum_of_subset_lcms(numbers, include_empty=False))
20print(sum_of_subset_lcms(numbers, include_empty=True))

This solution is easy to verify and is usually the right first version. It also makes testing simple because you can check small inputs by hand.

Reducing Repeated Work

The expensive part is not the lcm function by itself. The real cost comes from visiting all subsets, which is inherently 2^n work. Still, you can avoid recomputing the LCM of the same partial prefix again and again.

A recursive version can carry the current LCM forward:

python
1from math import lcm
2
3
4def sum_with_recursion(values, include_empty=False):
5    total = 1 if include_empty else 0
6
7    def dfs(index, current_lcm, picked_any):
8        nonlocal total
9        if index == len(values):
10            if picked_any:
11                total += current_lcm
12            return
13
14        dfs(index + 1, current_lcm, picked_any)
15
16        next_lcm = values[index] if not picked_any else lcm(current_lcm, values[index])
17        dfs(index + 1, next_lcm, True)
18
19    dfs(0, 1, False)
20    return total
21
22
23print(sum_with_recursion([2, 3, 4], include_empty=True))

This does not change the exponential nature of the problem, but it avoids rebuilding each subset tuple and avoids recomputing the LCM from scratch for every branch.

When the Naive Method Stops Scaling

For n = 20, there are already more than one million subsets. That is still possible in optimized code for some inputs, but the growth is sharp. If the list can be much larger, you need to exploit number-theory structure rather than enumerate everything.

Typical improvements include grouping equal values, memoizing repeated LCM states, or deriving formulas from prime factorizations. Those methods are more specialized and harder to implement correctly, so they are worth it only when n is large enough that enumeration is no longer acceptable.

Common Pitfalls

The first pitfall is forgetting to define the empty subset. Many off-by-one disagreements in this problem are really convention disagreements.

The second is assuming duplicates do not matter. If the input is a list rather than a mathematical set, repeated values create different subsets by position. Decide whether you are processing a set of unique values or an arbitrary sequence.

The third is overflow in fixed-width languages. Python integers grow automatically, but Java, C, and C++ can overflow quickly when many LCM values become large.

The fourth is recomputing prime factorizations or full LCM chains unnecessarily. Even when the exponential subset count dominates, avoiding repeated work still helps.

Summary

  • The direct solution is to enumerate subsets, compute each subset LCM, and sum the results.
  • Define whether the empty subset contributes before you write the function.
  • A recursive carry-forward LCM version reduces repeated work without changing the overall exponential growth.
  • Small inputs are fine with brute force; large inputs need extra number-theory structure.
  • Watch for duplicates, overflow in fixed-width integers, and hidden convention mismatches.

Course illustration
Course illustration

All Rights Reserved.