最大整除子集_力扣笔记

1.题目:
给你一个由 无重复 正整数组成的集合 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]

来源:力扣(LeetCode)
链接:368.最大整除子集

思路:
虽然示例中给出的测试值都是有序的,其实应该先进行排序。
原始的思路是两次遍历。

该问题是一个序列DP问题:状态的转移依赖前一个状态。
定义:dp[i]为考虑前i个数字,且以第i个数位结尾的最长[整除子集]长度。
存在两种情况:

  1. 如果在i之前找不到符合的nums[i]%nums[j]==0的位置j,那么nums[i]不能接在位置i的任何数后面,此时dp[i]=1
  2. 如果在i之前能够找到符合条件的位置j,则取所有符合条件的f[j]的最大值,代表如果希望找到以nums[i]为结尾的最长[整除子集],需要将nums[i]接到符合条件的最长的nums[j]后面,此时dp[i] = dp[j]+1
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

public class LargestDivisibleSubset {
    public List<Integer> largestDivisibleSubset(int[] nums)
    {
        Arrays.sort(nums);
        int n = nums.length;
        int[] dp = new int[n];
        int[] backup = new int[n];
        for (int i = 0;i < n;i++)
        {
            System.out.println(nums[i]+":");
            //至少包含自身一个数,因此起始长度为1,由自身转移得到
            int len = 1, prev = i;
            for (int j = 0;j < i;j++)
            {
                if (nums[i] % nums[j] == 0)
                {
                    System.out.format("nums[%d]:%d/nums[%d]:%d\n",i,nums[i],j,nums[j]);
                    //如果能接在更长的序列后面,则更新最长序列和由何转移得到
                    if (f[j] + 1 > len)
                    {
                        System.out.format("len:%d=f[%d]:%d+1\n",len,j,dp[j]);
                        len = dp[j] + 1;
                        prev = j;
                    }
                }
            }
            //记录最终长度和从何转移而来
            dp[i] = len;
            backup[i] = prev;
            System.out.println("");
        }
        //遍历所有的f[i],取得最长
        int max = -1, idx = -1;
        for (int i = 0;i < n;i++)
        {
            if (dp[i] > max)
            {
                idx = i;
                max = dp[i];
            }
        }
        //使用g[]数组回溯出具体方案
        List<Integer> ans = new ArrayList<>();
        while (ans.size() != max)
        {
            ans.add(nums[idx]);
            idx = backup[idx];
        }
        return ans;
    }
    public static void main(String[] args) {
        LargestDivisibleSubset LDS = new LargestDivisibleSubset();
        List<Integer> res;
        int []nums = {1,2,4,8};
        res = LDS.largestDivisibleSubset(nums);
        for (int i = 0;i < res.size();i++)
        {
            System.out.format("%d\t", res.get(i));
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值