最大整除子集

给出一个由无重复的正整数组成的集合,找出其中最大的整除子集,子集中任意一对 (Si,Sj) 都要满足:Si % Sj = 0 或 Sj % Si = 0。

如果有多个目标子集,返回其中任何一个均可。

示例 1:

输入: [1,2,3]
输出: [1,2] (当然, [1,3] 也正确)

示例 2:

输入: [1,2,4,8]
输出: [1,2,4,8]

这道题和找最长子序列有点像!

  1. 排序
  2. 动态规划找到最长的整除子集,但是要记录前一个数位置

举个例子 [1,2,3]

我们用dp[i]记录到i最长的整除子集长度,用pre[i]记录到i前面一个数的位置

很明显dp[0] = 1 ,pre[0] = -1

当i = 1,有nums[1] % nums[0] == 0可以整除,如果dp[0] + 1 > dp[1],那么pre[1] = 0,dp[1] = 2

当i = 2,也有有nums[2] % nums[0] == 0可以整除,那么我们判断i=2之前可以整除的,有nums[2] % nums[1] != 0,所以有nums[2] % nums[0] == 0能整除,有dp[0] + 1 > dp[2],

那么pre[2] = 0,dp[1] = 2

接下来我们就取dp最大值,即最长的整除子集长度,再根据记录的前面数的位置找出所有的数字

public List<Integer> largestDivisibleSubset(int[] nums) {
       int len = nums.length, m = 0, mi = 0;
        int[] dp = new int[len];
        int[] prev = new int[len];

        Arrays.sort(nums);

        for (int i = 0; i < len; i++) {
            for (int j = i; j >= 0; j--) {
                if (nums[i] % nums[j] == 0 && dp[j] + 1 > dp[i]) {
                    dp[i] = dp[j] + 1;
                    prev[i] = j;
                }
            }
            if (dp[i] > m) {
                m = dp[i];
                mi = i;
            }
        }

        List<Integer> res = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            res.add(nums[mi]);
            mi = prev[mi];
        }

        return res;
    
    }
}
原文地址:https://www.cnblogs.com/du001011/p/10817185.html