[LintCode] Largest Divisible Subset

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.

Example

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)

posted on 2017-05-26 12:31  codingEskimo  阅读(145)  评论(0编辑  收藏  举报

导航