https://leetcode-cn.com/problems/largest-divisible-subset/
思路:若
n
u
m
s
[
i
]
nums[i]
nums[i]可以整除
n
u
m
s
[
j
]
nums[j]
nums[j],我们认为从
i
i
i到
j
j
j有一条边,那么
O
(
n
2
)
O(n^2)
O(n2)处理数组后就得到了一张图,问题就转换为求这张图上的最长路径。有两种做法,第一spfa求最长路;第二先把图转换为有向无环图,然后利用dp求DAG上最长路。先给出第一种做法的代码:
class Solution {
public:
vector<vector<bool>> m;
vector<int> dis;
vector<int> pre;
int n;
void spfa(int st)
{
vector<bool> inque(n);
queue<int> q;
dis[st]=1;
inque[st]=1;
q.push(st);
while(!q.empty())
{
int fon=q.front();
inque[fon]=0;
q.pop();
for(int i=0;i<n;i++)
{
if(m[fon][i]&&dis[i]<dis[fon]+1)
{
dis[i]=dis[fon]+1;
pre[i]=fon;
if(!inque[i])
inque[i]=1,q.push(i);
}
}
}
}
vector<int> largestDivisibleSubset(vector<int>& nums) {
sort(nums.begin(),nums.end());
n=nums.size();
m.resize(n,vector<bool>(n));
dis.resize(n);
pre.resize(n,-1);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
if(nums[j]%nums[i]==0)
m[i][j]=1;
for(int i=0;i<n;i++)
if(!dis[i])
spfa(i);
int last=0;
for(int i=1;i<n;i++)
if(dis[i]>dis[last])
last=i;
vector<int> ans;
while(last>=0)
{
ans.push_back(nums[last]);
last=pre[last];
}
return ans;
}
};
下面我们来看第二种做法,如果要把一张图转换为有向无环图,则需要做拓扑排序,但是没有必要这么麻烦。只要我们先把数组排序,保证每一条有向边 ( i , j ) (i,j) (i,j)都满足 i < j i<j i<j,那么我们得到的一定是一张有向无环图,直接 d p dp dp即可。
class Solution {
public:
vector<int> largestDivisibleSubset(vector<int>& nums) {
sort(nums.begin(),nums.end());
int n=nums.size();
int maxsiz=0,curnum=0;
vector<int> dp(n);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
if(nums[j]%nums[i]==0)
{
dp[j]=max(dp[j],dp[i]+1);
if(dp[j]>maxsiz)
maxsiz=dp[j],curnum=nums[j];
}
vector<int> ans;
for(int i=n-1;i>=0;i--)
{
if(dp[i]==maxsiz&&curnum%nums[i]==0)
{
ans.push_back(nums[i]);
--maxsiz;
curnum=nums[i];
}
}
return ans;
}
};