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

简介:

Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.

If there are multiple solutions, return any subset is fine.

Example 1:

nums: [1,2,3]
Result: [1,2] (of course, [1,3] will also be ok)

Example 2:

nums: [1,2,4,8]
Result: [1,2,4,8]

Credits:
Special thanks to @Stomach_ache for adding this problem and creating all test cases.

这道题给了我们一个数组,让我们求这样一个子集合,集合中的任意两个数相互取余均为0,而且提示中说明了要使用DP来解。那么我们考虑,较小数对较大数取余一定不为0,那么问题就变成了看较大数能不能整除这个较小数。那么如果数组是无序的,处理起来就比较麻烦,所以我们首先可以先给数组排序,这样我们每次就只要看后面的数字能否整除前面的数字。定义一个动态数组dp,其中dp[i]表示到数字nums[i]位置最大可整除的子集合的长度,还需要一个一维数组parent,来保存上一个能整除的数字的位置,两个整型变量mx和mx_idx分别表示最大子集合的长度和起始数字的位置,我们可以从后往前遍历数组,对于某个数字再遍历到末尾,在这个过程中,如果nums[j]能整除nums[i], 且dp[i] < dp[j] + 1的话,更新dp[i]和parent[i],如果dp[i]大于mx了,还要更新mx和mx_idx,最后循环结束后,我们来填res数字,根据parent数组来找到每一个数字,参见代码如下:

解法一:

class Solution {
public:
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<int> dp(nums.size(), 0), parent(nums.size(), 0), res;
        int mx = 0, mx_idx = 0;
        for (int i = nums.size() - 1; i >= 0; --i) {
            for (int j = i; j < nums.size(); ++j) {
                if (nums[j] % nums[i] == 0 && dp[i] < dp[j] + 1) {
                    dp[i] = dp[j] + 1;
                    parent[i] = j;
                    if (mx < dp[i]) {
                        mx = dp[i];
                        mx_idx = i;
                    }
                }
            }
        }
        for (int i = 0; i < mx; ++i) {
            res.push_back(nums[mx_idx]);
            mx_idx = parent[mx_idx];
        }
        return res;
    }
};

下面这种方法和上面解法的思路基本一样,只不过dp数组现在每一项保存一个pair,相当于上面解法中的dp和parent数组揉到一起表示了,然后的不同就是下面的方法是从前往后遍历的,每个数字又要遍历到开头,参见代码如下:

解法二:

class Solution {
public:
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<int> res;
        vector<pair<int, int>> dp(nums.size());
        int mx = 0, mx_idx = 0;
        for (int i = 0; i < nums.size(); ++i) {
            for (int j = i; j >= 0; --j) {
                if (nums[i] % nums[j] == 0 && dp[i].first < dp[j].first + 1) {
                    dp[i].first = dp[j].first + 1;
                    dp[i].second = j;
                    if (mx < dp[i].first) {
                        mx = dp[i].first;
                        mx_idx = i;
                    }
                }
            }
        }
        for (int i = 0; i < mx; ++i) {
            res.push_back(nums[mx_idx]);
            mx_idx = dp[mx_idx].second;
        }
        return res;
    }
};

本文转自博客园Grandyang的博客,原文链接:最大可整除的子集合[LeetCode] Largest Divisible Subset ,如需转载请自行联系原博主。

相关文章
|
5月前
Leetcode 368. Largest Divisible Subset思路及详解
这里有个很简单的数学性质,就是整除的传递性,如果a%b==0 且 b%c == 0,那么a%c == 0,说白了如果c是b的因子,b又是a的因子,那么c肯定是a的因子。这样我们就可以在数组中找出很多整除链(a->b->c->d,其中b是a的因子,c是b的因子,d是c的因子),这样的链条就满足两两整除的条件,题目就变成了求最长的链条。 先上代码,然后我再解释下我的代码。
23 0
|
4月前
[leetcode 数位计算]2520. 统计能整除数字的位数
[leetcode 数位计算]2520. 统计能整除数字的位数
|
索引
LeetCode 368. Largest Divisible Subset
给出一个由无重复的正整数组成的集合,找出其中最大的整除子集,子集中任意一对 (Si,Sj) 都要满足:Si % Sj = 0 或 Sj % Si = 0。 如果有多个目标子集,返回其中任何一个均可。
57 0
LeetCode 368. Largest Divisible Subset
【LeetCode1262】 可被三整除的最大和(动态规划)
要从给出的数组中,找到一小坨数满足和能被3整除。dp[i][*]表示在num[i]中,被3整除后的余数为*的最大数(和)。 2.1 确定状态
111 0
【LeetCode1262】 可被三整除的最大和(动态规划)
|
算法
​LeetCode刷题实战368:最大整除子集数
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !
99 0
LeetCode 5449. 检查数组对是否可以被 k 整除(195周赛)
给你一个整数数组 arr 和一个整数 k ,其中数组长度是偶数,值为 n 。 现在需要把数组恰好分成 n / 2 对,以使每对数字的和都能够被 k 整除。
258 0
|
26天前
|
机器学习/深度学习 算法
力扣刷题日常(一)
力扣刷题日常(一)
20 2
|
1月前
|
存储 索引
《LeetCode》—— LeetCode刷题日记
《LeetCode》—— LeetCode刷题日记
|
1月前
|
搜索推荐
《LeetCode》——LeetCode刷题日记3
《LeetCode》——LeetCode刷题日记3

热门文章

最新文章