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
.
Notice: If there are multiple solutions, return any subset is fine.
Given nums = [1,2,3]
, return [1,2]
or [1,3]
Given nums = [1,2,4,8]
, return [1,2,4,8]
题意:给定一个数组,求其中的一个最大子集,要求该子集中任意的两个元素满足 x % y ==0 或者 y % x==0
思路:其实和求最大上升子序列LIS差不多,只不过这题要求输出序列而已。
先把数组排好序。首先要明确,若a<b且b%a==0 , b <c 且 c%b==0那么必然有c%a==0
在这里f[i]是代表在第i 位置上,最大的可以整除的子集的size。因为至少每个数都可以被自己整除,所以f[i]至少等于1。当一个数可以整除一个比它小的数(前面的数),那么我们需要比较这个点现在的f[i]和对应被整除那个点f[j] + 1的值哪个更大,需要+1是因为f[i]比f[j]多了一个可以整除的数。我们可以通过比较大小得到f中最大的数的值和对应的index。这个最大值就说明最后结果的size。
这道题比较tricky的部分是它需要另一个数组prev来记录上一个可以被nums[i]被整除的数的index。需要这个是因为最后我们需要能找到把哪些数字放到list里面。通过这个数组,我们可以一直追踪回去。只有当prev[i]和i相等的时候,说明前面已经没有可以被整除的数了,这个就是最小的值了。我们停止loop并把最后一个数加回来。
注意:因为除数一定要大于被除数,为了计算方便,已及减少重复和漏洞,一定要先排序。且排序这里不会增加本题的时间复杂度
public class Solution { /** * @param nums a set of distinct positive integers * @return the largest subset */ public List<Integer> largestDivisibleSubset(int[] nums) { // Write your code here if (nums == null || nums.length == 0) { return null; } Arrays.sort(nums); int n = nums.length; int[] f = new int[n]; //f[i] the largest subset number from previous element to i int[] prev = new int[n]; //prev[i] the previous largest subset that could be dividable for (int i = 1; i < n; i++) { f[i] = 0; prev[i] = i; for (int j = 0; j < i; j++) { if (nums[i] % nums[j] == 0 && f[i] < f[j] + 1) { prev[i] = j; f[i] = f[j] + 1; } } } int max = Integer.MIN_VALUE; int maxIdx = 0; for (int i = 0; i < n; i++) { if (max < f[i]) { max = f[i]; maxIdx = i; } } List<Integer> rst = new ArrayList<Integer>(); while (prev[maxIdx] != maxIdx) { rst.add(nums[maxIdx]); maxIdx = prev[maxIdx]; } rst.add(nums[maxIdx]); return rst; } }
这道题的时间复杂度应该接近O(n^2)