LeetCode 368. Largest Divisible Subset

题目

在这里插入图片描述

分析

看上去是很复杂的题目,需要去搜索。搜索的复杂度就是指数级的了,如果数很多就不现实了。换种思路,根据整除的传递性,比如4可以整除以2,8可以整除以4,所以8自然可以整除以2,我们就可以简化这个问题为一个dp问题。但是需要先对数组排序
dp[i] 表示数组中第i个元素和之前的数能组成的最多的整除集合的数量,初始值显然是1,就是本身一个元素作为集合。
然后对每个数,遍历它之前的所有数,由于数字已经排好序了,所以后面的数只需要检查前面的每一个数,如果能够整除某个数nums[j],那就比较一下dp[j] + 1和dp[i]的大小,保留较大的。由于题目是要找最大的集合,所以为了省去最后的遍历,再用个变量存一下最大的集合数量值。

题目还要求我们把这个子集给找出来,所以我们需要额外开辟一个数组pre,pre[i]保存的是nums[i]组成的最大整除数组中的上一个被整除的元素的位置,初始化为-1。比如说1 2 4 8,那么pre的值就分别是-1,0,1,2,这样最后我们只需要根据pre,递归回溯找到这个最大子集从而解决问题。下面来看代码

代码

class Solution {
public:
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        int n = nums.size();
        if (n <= 1) return nums;
        sort(nums.begin(), nums.end());
        vector<int>dp(n, 1), pre(n, -1);
        // 最大子集长度maxlen和这个子集的最大元素的下标maxpos
        int maxlen = 0, maxpos = -1;
        for (int i = 1; i < nums.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (nums[i] % nums[j] != 0) continue;
                else {
                	// 更新每个位置的dp和pre值
                    if (dp[j] + 1 > dp[i]) {
                        dp[i] = dp[j] + 1;
                        pre[i] = j;
                    }
                    // 找到更大的子集了 更新maxlen maxpos
                    if (dp[i] > maxlen) {
                        maxlen = dp[i];
                        maxpos = i;
                    }
                }
            }
        }
        vector<int>ans;
        // 边界情况,如果所有元素互质,那只需要随便返回数组中一个元素即可,不妨返回第一个
        if (maxpos == -1) {
            ans.push_back(nums.front());
            return ans;
        }
        // 一般情况,递归找到所有的集合元素,最后一个pre肯定是-1
        while (maxpos != -1) {
            ans.push_back(nums[maxpos]);
            maxpos = pre[maxpos];
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值