368. 最大整除子集(序列dp)

Posted mp-ui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了368. 最大整除子集(序列dp)相关的知识,希望对你有一定的参考价值。

368. 最大整除子集

题目描述

368. 最大整除子集
给你一个由 无重复 正整数组成的集合 nums ,请你找出并返回其中最大的整除子集 answer ,子集中每一元素对 (answer[i], answer[j]) 都应当满足:
answer[i] % answer[j] == 0 ,或
answer[j] % answer[i] == 0
如果存在多个有效解子集,返回其中任何一个均可。

 

示例 1:

输入:nums = [1,2,3]
输出:[1,2]
解释:[1,3] 也会被视为正确答案。
示例 2:

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

提示:

1 <= nums.length <= 1000
1 <= nums[i] <= 2 * 109
nums 中的所有整数 互不相同
通过次数35,218提交次数77,473

请添加图片描述

题解

参考题目:300. 最长递增子序列

这道题目可以采用动态规划来解。相当于最长递增子序列的解法,我们假定dp[i] 代表以 nums[i]结尾的最大整除子集的元素个数,解答过程和最长递增子序列的类似,最长递增子序列这道题的if判断那里是nums[i] > nums[j],而这里是nums[i] % nums[j] == 0

最后,我们就可以轻而易举地求解出最大整除子集的元素个数,但是题目并不是要求我们求出长度,而是求出长度最长的那个List

所以,为了方便求出路径,我们使用数组g来记录,定义g[i]为最大整除子集中nums[i]的上一个元素在nums数组对应的下标。

最后通过回溯来求就行了(这里就像是用BFS求迷宫最短路径,也是需要用一个数组来记录)

代码如下:

class Solution {
    public List<Integer> largestDivisibleSubset(int[] nums) {
        Arrays.sort(nums);  //【踩坑!!!】需要排序一下
        int n = nums.length;
        //类似题目:300. 最长递增子序列
        int[] dp = new int[n];  //dp[i]:以nums[i]结尾的最大整除解集的元素个数
        int[] g = new int[n];   //g[i]:nums[i]的上一个
        for (int i = 0; i < n; i++) {
            dp[i] = 1;
            g[i] = -1;
            for (int j = i - 1; j >= 0; j--) {
                if(nums[i] % nums[j] == 0){
                    //能整除
                    if(dp[i] < dp[j] + 1){
                        dp[i] = dp[j] + 1;
                        g[i] = j;   //表示nums[i]的上一个是nums[j]
                    }
                }
            }
        }
        //遍历dp,找到最大的那个
        int maxI = 0;       //记录最大值的下标
        int maxV = dp[0];   //记录最大值
        for (int i = 0; i < dp.length; i++) {
            if(dp[i] > maxV){
                maxI = i;
                maxV = dp[i];
            }
        }
        //获取到最大的之后,通过回溯g数组来获得最大整除子集
        LinkedList<Integer> res = new LinkedList<>();
        int times = 0;  //记录次数
        int now = maxI; //当前下标
        while(times < maxV && now != -1){
            //最长子集里面有maxV个数,所以回溯maxV次
            res.addFirst(nums[now]);
            now = g[now];
            ++times;
        }
        return res;
    }
}

运行结果:

请添加图片描述

以上是关于368. 最大整除子集(序列dp)的主要内容,如果未能解决你的问题,请参考以下文章

leetcode368. Largest Divisible Subset

LeetCode 0368. 最大整除子集

leetcode 368

2021春季每日一题week6 未完结

最大整除子集

java 368.最大的可分子集(#1).java