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. 最大整除子集的主要内容,如果未能解决你的问题,请参考以下文章