题目大意
给出一个由无重复的正整数组成的集合,找出其中最大的整除子集,子集中任意一对 (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]
解题思路
题目中说可以是Si % Sj = 0 或 Sj % Si = 0,为了方便起见,我们首先对数组排序,总是用大数去除以小数。
接下来是动态规划的思想。当遍历到位置i时,遍历0~i-1位置的元素,如果能够被nums[i]整除,则dp[i]=max(dp[i], dp[j]+1),即dp[i]表示的是:数组中最大值是nums[i]时,能够组成的最长序列的长度。同时每次把最大长度和最大值的索引记录下来。
当遍历完数组后(O(N2)),从最大索引位置向前遍历,如果该位置的值能够被记录的最大值整除,则加入最后结果中(需要注意的是,6%2=0, 6%3=0,但是2和3并不满足关系,因此要满足dp[i]要满足和最大长度的关系)。
class Solution {
public:
vector<int> largestDivisibleSubset(vector<int>& nums) {
if (nums.empty())
return {};
if (nums.size() == 1)
return {nums[0]};
sort(nums.begin(), nums.end());
int maxIndex = 0, maxCount = 1;
int length = nums.size();
vector<int> dp(length, 1);
for (int i = 1; i < length; ++i){
for (int j = 0; j < i; ++j){
if (nums[i] % nums[j] == 0)
dp[i] = max(dp[i], dp[j] + 1);
}
if (dp[i] > maxCount){
maxCount = dp[i];
maxIndex = i;
}
}
vector<int> res;
int firstNum = nums[maxIndex];
for (int i = maxIndex; i >= 0; --i){
if (firstNum % nums[i] == 0 && dp[i] == maxCount){
res.push_back(nums[i]);
// 防止出现6%2=0和6,但2和3不满足关系的情况
--maxCount;
}
}
return res;
}
};