Largest Divisible Subset -- LeetCode
Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.
If there are multiple solutions, return any subset is fine.
Example 1:
nums: [1,2,3]
Result: [1,2] (of course, [1,3] will also be ok)
Example 2:
nums: [1,2,4,8]
Result: [1,2,4,8]
思路: DP。
假设有一个集合,集合内的数两两可除。现在有一个新的数,则该数能加入这个集合中的条件是:集合里最小的数能被这个数整除,或者这个数能够被数组中最大的数整除。
例子:假设集合为{4, 8, 16}, 现在有2,因此4能被2整除,因此2能加入这个数组。如果是32,则32能被16整除,因此也可以加入这个数组。
这道题,我们先把nums数组升序排序。
创建一个数组count[i]表示nums[i]到nums.back()这些数中,包含nums[i]的最大可除集合的大小。显然,nums[i]是这个最大可除集合中的最小的数。
根据上面判断一个新元素能否加入集合中的判断方法,count[i] = max{1 + count[j]} (i < j 且 nums[j] % nums[i] == 0)
同时我们维护另一个数组parent[i]表示从nums[i]到nums.back()这些数中,包含nums[i]的最大可除集合中的第二大的数。初始时这个parent[i] = i。
最后,我们维护一个head指针,它在计算过程中始终指向当前已知的最大可除集合中的最小值。然后通过parent数组我们就能遍历这个集合中的所有的数。
算法时间复杂度O(n^2),空间复杂度为O(n)。
1 class Solution { 2 public: 3 vector<int> largestDivisibleSubset(vector<int>& nums) { 4 vector<int> res; 5 if (nums.size() == 0) return res; 6 vector<int> count(nums.size(), 1); 7 vector<int> parent(count); 8 int head = 0, maxLen = 0; 9 sort(nums.begin(), nums.end(), less<int>()); 10 for (int i = nums.size() - 1; i >= 0; i--) { 11 parent[i] = i; 12 for (int j = i + 1; j < nums.size(); j++) { 13 if (nums[j] % nums[i] == 0 && count[i] < 1 + count[j]) { 14 count[i] = 1 + count[j]; 15 parent[i] = j; 16 if (maxLen < count[i]) { 17 maxLen = count[i]; 18 head = i; 19 } 20 } 21 } 22 } 23 res.push_back(nums[head]); 24 while (head != parent[head]) { 25 head = parent[head]; 26 res.push_back(nums[head]); 27 } 28 return res; 29 } 30 };