Largest Divisible Subset
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ nums.length ≤ 10 - ◆
1 ≤ nums[i] ≤ 1000 - ◆
All the integers in nums are distinct - ◆
If more than one largest divisible subset exists, return the one built by sorting nums ascending first and always preferring the smallest-index predecessor whenever two predecessors would extend a chain to the same length
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Recursive Without Memoization
BruteSort the array first, since any divisible chain must appear in increasing order once sorted — a later, larger multiple can only ever divide evenly by an earlier, smaller factor. For each starting index, recursively try every later index that the current number divides evenly into, chase the longest chain reachable from there, and prepend the current number to whatever comes back. Repeating that from every possible starting index and keeping the longest result overall finds the answer, but the same "best chain starting here" question gets solved again from scratch every time a different earlier chain happens to reach the same index.
O(2^n)O(n)1class Solution {
2 private int[] nums;
3
4 public int[] largestDivisibleSubset(int[] nums) {
5 Arrays.sort(nums);
6 this.nums = nums;
7 List<Integer> best = new ArrayList<>();
8 for (int i = 0; i < nums.length; i++) {
9 List<Integer> candidate = solve(i);
10 if (candidate.size() > best.size()) best = candidate;
11 }
12 int[] out = new int[best.size()];
13 for (int k = 0; k < out.length; k++) out[k] = best.get(k);
14 return out;
15 }
16
17 private List<Integer> solve(int i) {
18 List<Integer> best = new ArrayList<>();
19 for (int j = i + 1; j < nums.length; j++) {
20 if (nums[j] % nums[i] == 0) {
21 List<Integer> candidate = solve(j);
22 if (candidate.size() > best.size()) best = candidate;
23 }
24 }
25 List<Integer> result = new ArrayList<>();
26 result.add(nums[i]);
27 result.addAll(best);
28 return result;
29 }
30}Optimal — Bottom-Up DP with Parent Pointers
OptimalSort the array first, for the same reason as above — once sorted, a divisible chain is automatically an increasing sequence, so this becomes the Longest Increasing Subsequence pattern with "nums[i] % nums[j] == 0" in place of "nums[j] < nums[i]". Let dp[i] hold the length of the best divisible chain ending at index i: check every earlier index j, and whenever nums[i] divides evenly by nums[j], dp[i] can extend dp[j] by one. A parent[i] array records which earlier index produced that best length, updating only on a strict improvement so the first qualifying predecessor at a given length wins ties. The index with the largest dp value marks where the answer ends, and walking parent pointers back from there — filling a result array from its last slot toward its first — rebuilds the actual chain in one pass.
O(n²)O(n)1class Solution {
2 public int[] largestDivisibleSubset(int[] nums) {
3 Arrays.sort(nums);
4 int n = nums.length;
5 int[] dp = new int[n];
6 Arrays.fill(dp, 1);
7 int[] parent = new int[n];
8 Arrays.fill(parent, -1);
9 for (int i = 1; i < n; i++) {
10 for (int j = 0; j < i; j++) {
11 if (nums[i] % nums[j] == 0 && dp[j] + 1 > dp[i]) {
12 dp[i] = dp[j] + 1;
13 parent[i] = j;
14 }
15 }
16 }
17 int maxIdx = 0;
18 for (int i = 1; i < n; i++) {
19 if (dp[i] > dp[maxIdx]) maxIdx = i;
20 }
21 int[] result = new int[dp[maxIdx]];
22 int pos = dp[maxIdx] - 1;
23 int cur = maxIdx;
24 while (cur != -1) {
25 result[pos--] = nums[cur];
26 cur = parent[cur];
27 }
28 return result;
29 }
30}