题目描述
给你一个由 无重复 正整数组成的集合 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 中的所有整数 互不相同
题目分析:
这一题我们可以使用动态规划来完成,那么关键是找出我们应该表示什么状态和状态的转移方程。在这一题中我们要求的是最大的整除子集,那么很容易想到用数组dp,其中dp[i]表示包括nums[i]在内的,nums[0],nums[1],nums[2],…nums[i]内最大的整除子集。注意,这里nums[i]必须被选择。
那么dp[[0-N]都应该被初始化值为1。
接下来考虑状态的转移:
枚举nums[0],nums[1],…nums[i-1]内所有元素,如果nums[i]能够整除它们,就该让dp[i]=Math.max(dp[i],dp[j]+1),注意这里不能简单的让dp[i]++。我们可以简单举一个例子说明这个道理:
[4,8,10,240]这个数组,如果我们每枚举一次能够整除让dp[i]++,那么dp[3]就应该等于4。实际上10不能够整除4和8,因此是错误的。因为这样不能够保证子集内部都能被整除。
我们这样做仅仅只是找到了最大的整除子集长度,那么怎么找到对应的元素集合呢?试想,假设MAX(dp[i])==4,那么我们只需要顺势找到dp[i]==3,dp[i]==2,dp[i]==1的几种情况,如果dp[i]==4时最大的元素maxVal能够整除dp[i]==3时对应位置的元素,那么就加入该元素到集合中。同时MaxVal应该对应dp[i]==3时对应的元素,因为dp[i]==3的位置可能有多个,我们必须保证我们找到的是正确的。
具体程序:
class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> lists=new ArrayList<>();
int n=nums.length,i,j;
int []dp=new int[n];
Arrays.fill(dp,1);
Arrays.sort(nums);
int maxSize=1,maxVal=nums[0];
for(i=1;i<n;i++){
for(j=0;j<i;j++){
if(nums[i]%nums[j]==0) dp[i]=Math.max(dp[i],dp[j]+1);//状态转移方程很重要
}
maxSize=Math.max(maxSize,dp[i]);
if(maxSize==dp[i]) maxVal=nums[i];
}
for(i=n-1;i>=0&& maxSize>0;i--){
if(maxSize==dp[i] && maxVal%nums[i]==0){
maxSize--;
lists.add(nums[i]);
**maxVal=nums[i];//必须让maxVal=nums[i];**
}
}
return lists;
}
}
``