The largest chain of divisors
Given distinct positive integers nums, return the size of the largest subset in which, for every pair
(a, b), either a divides b or b divides a.
Examples
| Input | Output | Why |
|---|---|---|
nums = [1,2,3] | 2 | {1, 2} or {1, 3}. |
nums = [1,2,4,3,8,6,24] | 5 | {1, 2, 4, 8, 24}. |
nums = [2,3,5,7] | 1 | Primes: no pair works. |
Constraints
- 1 ≤ nums.length ≤ 1000
- 1 ≤ nums[i] ≤ 2 · 10⁹, all distinct
Hints
Hint 1
Sort the numbers. In a valid subset, each element then divides the next.
Hint 2
Divisibility is transitive: if a | b and b | c then a | c, so checking neighbours is enough.
Hint 3
end[i] = 1 + max end[j] over j < i with nums[i] % nums[j] == 0.
Where people lose marks
- Not sorting first, so a divisor can appear after its multiple.
- Checking every pair in the chain instead of relying on transitivity (correct, but slower).
Dry run on [1,2,4,3,8,6,24]
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 7sorted102132436485246end10·1·2·3·4·5·6
1 is a multiple of nothing earlier: end = 1.
-
Step 2 / 7sorted102132436485246end1021·2·3·4·5·6
2 is a multiple of 1: end = 2.
-
Step 3 / 7sorted102132436485246end102122·3·4·5·6
3 is a multiple of 1: end = 2.
-
Step 4 / 7sorted102132436485246end10212233·4·5·6
4 is a multiple of 1, 2: end = 3.
-
Step 5 / 7sorted102132436485246end1021223334·5·6
6 is a multiple of 1, 2, 3: end = 3.
-
Step 6 / 7sorted102132436485246end102122333445·6
8 is a multiple of 1, 2, 4: end = 4.
-
Step 7 / 7sorted102132436485246end10212233344556
24 is a multiple of 1, 2, 3, 4, 6, 8: end = 5. The answer is 5.
How to think about it
After sorting, a valid subset listed in increasing order has each element dividing the next, and because divisibility
is transitive, that is also sufficient. So the problem is a longest chain in the sorted list where "compatible" means
"divides": the subsequence pattern. end[i] = 1 + max(end[j]) over earlier j with
nums[i] % nums[j] = 0, and the answer is the largest end[i].
Complexity. Time O(n²) · Space O(n)
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def largest_divisible_subset(nums):
a = sorted(nums) # then each element must divide the next
end = [1] * len(a)
for i in range(len(a)):
for j in range(i):
if a[i] % a[j] == 0:
end[i] = max(end[i], end[j] + 1)
return max(end)#include <algorithm>
#include <vector>
int solve(std::vector<long long> nums) {
std::sort(nums.begin(), nums.end()); // then each element divides the next
std::vector<int> end(nums.size(), 1);
for (size_t i = 0; i < nums.size(); ++i)
for (size_t j = 0; j < i; ++j)
if (nums[i] % nums[j] == 0) end[i] = std::max(end[i], end[j] + 1);
return *std::max_element(end.begin(), end.end());
}class Solution {
public int largestDivisibleSubset(int[] nums) {
int[] a = nums.clone();
java.util.Arrays.sort(a); // then each element divides the next
int[] end = new int[a.length];
int best = 0;
for (int i = 0; i < a.length; i++) {
end[i] = 1;
for (int j = 0; j < i; j++) if (a[i] % a[j] == 0) end[i] = Math.max(end[i], end[j] + 1);
best = Math.max(best, end[i]);
}
return best;
}
}function largestDivisibleSubset(nums) {
const a = [...nums].sort((x, y) => x - y);
const end = new Array(a.length).fill(1);
for (let i = 0; i < a.length; i++)
for (let j = 0; j < i; j++) if (a[i] % a[j] === 0) end[i] = Math.max(end[i], end[j] + 1);
return Math.max(...end);
}fn solve(nums: &[i64]) -> i64 {
let mut a = nums.to_vec();
a.sort(); // then each element divides the next
let mut end = vec![1i64; a.len()];
for i in 0..a.len() {
for j in 0..i {
if a[i] % a[j] == 0 {
end[i] = end[i].max(end[j] + 1);
}
}
}
*end.iter().max().unwrap()
}import Data.Array
import Data.List (sort)
solve :: [Int] -> Int
solve nums = maximum (elems end)
where
a = listArray (0, n - 1) (sort nums)
n = length nums
end = listArray (0, n - 1) [1 + maximum (0 : [end ! j | j <- [0 .. i - 1], a ! i `mod` a ! j == 0]) | i <- [0 .. n - 1]] :: Array Int Int
Variants to try
- Return the subset itself (store predecessors; LeetCode asks for this).
- Allow duplicates.
- Find the longest chain where each element is at least double the previous.
Next problems
How many longest increasing subsequences
Count the strictly increasing subsequences of maximum length. Keep, for each position, the best length ending there and how many subsequences achieve it.
Open the problem → Medium20 minThe longest rise-then-fall subsequence
Return the length of the longest subsequence that strictly increases and then strictly decreases. Run the increasing table from both ends and join them at the peak.
Open the problem → Medium20 minThe longest alternating subsequence
Return the length of the longest subsequence whose successive differences alternate between positive and negative. Two numbers carry the whole table.
Open the problem →Write a solution and run it against the real test table.
Keep going
How many longest increasing subsequences
Count the strictly increasing subsequences of maximum length. Keep, for each position, the best length ending there and how many subsequences achieve it.
Open the problem → Medium20 minThe longest rise-then-fall subsequence
Return the length of the longest subsequence that strictly increases and then strictly decreases. Run the increasing table from both ends and join them at the peak.
Open the problem → Medium20 minThe longest alternating subsequence
Return the length of the longest subsequence whose successive differences alternate between positive and negative. Two numbers carry the whole table.
Open the problem → Dynamic programmingThe pattern behind it
Write the recursion, notice the repeats, fill a table in an order that makes each entry final.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.