368. 最大整除子集

Posted fdwzy

tags:

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

题目:

链接:https://leetcode-cn.com/problems/largest-divisible-subset/

给出一个由无重复的正整数组成的集合,找出其中最大的整除子集,子集中任意一对 (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]

 

解答:

自己写的,能过,但不是最优算法。

思路是先排序,这样可以用大的除小的。把每个数能整除的数存入哈希表,之后遍历到num时,寻找所有小于num-1的数x中满足num%x==0的。取最大的那个,加上num本身作为dp[num]。

如[2,3,4,8,10],存为2:[2],3:[3],4:[2,4],8:[2,4,8],10:[2,4,8]。

代码:

 1 class Solution {
 2 public:
 3     vector<int> largestDivisibleSubset(vector<int>& nums) {
 4         if(nums.empty()){return {};}
 5         sort(nums.begin(),nums.end());
 6         unordered_map<int,vector<int>> mp;
 7         mp[nums[0]]={nums[0]};
 8         int max_pos=0,max_scale=0;
 9         for(int i=1;i<nums.size();++i){
10             int max_len=0,max_val;
11             for(auto& pai:mp){
12                 if(nums[i]%(pai.first)==0 and pai.second.size()>max_len){
13                     max_len=pai.second.size();
14                     max_val=pai.first;
15                 }
16             }
17             if(max_len>0){
18                 mp[nums[i]]=mp[max_val];
19             }
20             mp[nums[i]].push_back(nums[i]);
21             if(max_len+1>max_scale){
22                 max_scale=max_len+1;
23                 max_pos=i;
24             }
25         }
26         return mp[nums[max_pos]];
27     }
28 };

技术图片

 

 

 

做的时候也想到了上面解法的问题,即:存这么多遍路径没什么用,因为dp时比较的是路径长度,很多路径相当于白存了。

评论区大佬们的思路差不多,都是利用记录前缀节点来记录路径。比如2,4,8是一个子集,对于2只记录自己,4记录2,8记录4。最后查找路径的时候,逆序一路倒推回去就得到了整个子集。

这种做法需要一个记录前缀节点的数组和一个dp数组。

代码:

 1 class Solution {
 2 public:
 3     vector<int> largestDivisibleSubset(vector<int>& nums) {
 4         int sz = nums.size(),mx = 0,last = -1;
 5         vector<int> dp(sz,1),tail(sz,-1),res;
 6         sort(nums.begin(),nums.end());//还是得先排序
 7         for(int i = 0;i<sz;i++){
 8             for(int j = 0;j<i;j++){//这里是O(n),如果数据量大可以改二分查找。
 9                 if(nums[i]%nums[j] == 0 && dp[i]<=dp[j]){
10                     dp[i] = dp[j]+1;
11                     tail[i] = j;
12                 }
13             }
14             if(dp[i]>mx){
15                 mx = dp[i];
16                 last = i;
17             }
18         }
19         for(int i = last;i!=-1;i = tail[i]){//倒序输出
20             res.push_back(nums[i]);
21         }
22         return res;
23     }
24 };

技术图片

 

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

LeetCode 0368. 最大整除子集

leetcode368. Largest Divisible Subset

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

最大整除子集

不能被 K 整除的两个和的最大子集

[LeetCode] Largest Divisible Subset 最大可整除的子集合