368. 最大整除子集

题目链接:leetcode.

三重循环,但思路根本就是错的,哎
42 / 48 个通过测试用例
[5,9,18,54,108,540,90,180,360,720]
输出 [9,18,54,108,540]
预期结果 [9,18,90,180,360,720]

class Solution {
public:
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        int N = nums.size();
        vector<vector<int>> ans;
        int maxx = 0;
        for(int i = 0;i < N;++i)
        {
        	vector<int> tmp(1, nums[i]);
        	for(int j = i + 1;j < N;++j)
        	{
        		bool flag = true;
        		for(auto x : tmp)
        		{
        			if(nums[j] % x != 0 && x % nums[j] != 0)
        			{
        				flag = false;
        				break;
        			}
        		}
        		if(flag)
        		{
        			tmp.push_back(nums[j]);
        		}
        	}
            if(maxx < tmp.size())
                maxx = tmp.size();
        	ans.push_back(tmp);
        }
        for(int i = 0;i < N;++i)
        {
        	if(ans[i].size() == maxx)
        		return ans[i];
        }
        return {};
    }
};

原来是要用动态规划,如果之前做300. 最长递增子序列的时候我记住了该多好

如果一个数,是当前整除子集中最大数的倍数,则该数可以加入整除子集中构成一个更大的子集
利用这个思想,dp[i]存放以nums[i]为最大数的整除子集的长度,如果nums[j]nums[i]的倍数,则dp[j] = dp[i] + 1

  • 先对数组排序O(nlogn)
  • 初始化dp数组,所有的dp[i]都等于1,从前往后计算dp[i],每次计算都要遍历dp[0]dp[i-1],O(n^2)
  • 找出最大的整除子集的长度max_len O(n)

根据max_len求取最大整除子集 O(n)

  • 将对应max_len的数字num加入ans数组中,从num开始往前遍历,找到dp值为max_len - 1且能整除num的数,将其作为新的num,加入ansmax_len减一,继续向前遍历,直到max_len == 0
/*
执行用时:40 ms, 在所有 C++ 提交中击败了98.25%的用户
内存消耗:8.5 MB, 在所有 C++ 提交中击败了63.07%的用户
*/
class Solution {
public:
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int N = nums.size();
        vector<int> dp(N, 1);
        int max_len = 1;
        for(int i = 1;i < N;++i)
        {
        	int maxx = 0;
        	for(int j = 0;j < i;++j)
        	{
        		if(nums[i] % nums[j] == 0)
        		{
        			maxx = max(maxx, dp[j]);
        		}
        	}
        	dp[i] += maxx;
        	max_len = max(max_len, dp[i]);
        }
        vector<int> ans;
        for(int i = N - 1;i >= 0 && max_len;--i)
        {
        	if(dp[i] == max_len)
        	{
        		if(ans.empty())
        		{
        			ans.push_back(nums[i]);
        			max_len--;
        		}	
        		else if(ans.back() % nums[i] == 0)
        		{
        			ans.push_back(nums[i]);
        			max_len--;
        		}
        	}
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值