{x}
blog image

Largest Divisible Subset

Given a set of distinct positive integers nums, return the largest subset answer such that every pair (answer[i], answer[j]) of elements in this subset satisfies:

  • answer[i] % answer[j] == 0, or
  • answer[j] % answer[i] == 0

If there are multiple solutions, return any of them.

 

Example 1:

Input: nums = [1,2,3]
Output: [1,2]
Explanation: [1,3] is also accepted.

Example 2:

Input: nums = [1,2,4,8]
Output: [1,2,4,8]

 

Constraints:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 2 * 109
  • All the integers in nums are unique.

Solution Explanation for Largest Divisible Subset

The problem asks to find the largest subset from a given set of distinct positive integers where every pair of numbers (a, b) in the subset satisfies either a % b == 0 or b % a == 0. This means one number must be divisible by the other.

The optimal solution uses dynamic programming and sorting.

Approach:

  1. Sort the input array: Sorting allows us to efficiently check divisibility. If we have a sorted array, we only need to check divisibility for numbers that come before the current number in the sorted array.

  2. Dynamic Programming: We use an array f where f[i] represents the size of the largest divisible subset ending with nums[i]. Initially, f[i] = 1 for all i (a subset containing only nums[i] has size 1).

  3. Iteration: We iterate through the sorted array. For each number nums[i], we check all preceding numbers nums[j] (j < i). If nums[i] is divisible by nums[j], it means we can extend the largest divisible subset ending with nums[j] by adding nums[i]. Therefore, we update f[i] to be max(f[i], f[j] + 1).

  4. Finding the largest subset: After the iteration, the largest value in f indicates the size of the largest divisible subset. The index k of this largest value gives us the last element of that subset.

  5. Backtracking: We backtrack from nums[k] to find the other elements of the largest subset. We iterate backward, checking if nums[k] is divisible by nums[i] and if the size of the subset ending with nums[i] is one less than the size of the subset ending with nums[k]. If both conditions are true, nums[i] is part of the largest subset.

Time Complexity: O(n^2), where n is the length of the input array. This is because of the nested loops in the dynamic programming step.

Space Complexity: O(n) to store the f array and the result.

Code Explanation (Python):

class Solution:
    def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
        nums.sort()  # Sort the input array
        n = len(nums)
        f = [1] * n  # Initialize DP array
        k = 0  # Index of the last element of the largest subset
        for i in range(n):
            for j in range(i):
                if nums[i] % nums[j] == 0:  # Check divisibility
                    f[i] = max(f[i], f[j] + 1)  # Update DP array
            if f[k] < f[i]:  # Find the index of the largest subset
                k = i
        m = f[k]  # Size of the largest subset
        i = k
        ans = []  # Resultant largest subset
        while m:  # Backtrack to reconstruct the subset
            if nums[k] % nums[i] == 0 and f[i] == m:
                ans.append(nums[i])
                k, m = i, m - 1  # Move to the previous element in the subset
            i -= 1
        return ans
 

The Java, C++, and Go code follow the same logic, just with different syntax. The core dynamic programming and backtracking steps remain identical. The differences lie mainly in how arrays and lists are handled in each language.