import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this
* subset satisfies: Si % Sj = 0 or Sj % Si = 0.
* <p>
* If there are multiple solutions, return any subset is fine.
* <p>
* Example 1:
* <p>
* nums: [1,2,3]
* <p>
* Result: [1,2] (of course, [1,3] will also be ok)
* Example 2:
* <p>
* nums: [1,2,4,8]
* <p>
* Result: [1,2,4,8]
* <p>
* Tags: Dynamic Programming, Math
*/
public class LargestDivisibleSubset {
/**
* For a new integer S, S can be placed into the set as long as it can divide the smallest number of the set or is
* divisible by the largest number of the set.
* <p>
* Recurrent relation:
* T[n] = the length of the largest divisible subset whose largest number is a[n]
* T[n+1] = max{ 1 + T[i] } if a[n+1] mod a[i] == 0 for 0<=i<=n, else 1
* <p>
* Sort the array first.
* Create an array named parent to record parent index of current element.
* Create an array named count to record the largest subset of current element.
* Then Start from one end of the array and try to find larger element that divides current element.
* If it divides and subset size is smaller than that element + 1, then update size and parent.
* If count is bigger than max, update max and max index.
* Finally, recover the list of integers with parent array.
*/
public List<Integer> largestDivisibleSubset(int[] nums) {
if (nums == null) throw new NullPointerException("Input array nums is null");
if (nums.length <= 1) throw new IllegalArgumentException("Input array must have at least 2 elements");
Arrays.sort(nums);
int[] parent = new int[nums.length];
int[] count = new int[nums.length];
int max = 0;
int maxIndex = -1;
for (int i = nums.length - 1; i >= 0; i--) {
for (int j = i; j < nums.length; j++) {
if (nums[j] % nums[i] == 0 && count[i] < 1 + count[j]) {
count[i] = 1 + count[j];
parent[i] = j;
if (count[i] > max) {
max = count[i];
maxIndex = i;
}
}
}
}
List<Integer> res = new ArrayList<>();
for (int i = 0; i < max; i++) {
res.add(nums[maxIndex]);
maxIndex = parent[maxIndex];
}
return res;
}
}