368. 最大整除子集
368. 最大整除子集
🟠 🔖 数组
数学
动态规划
排序
🔗 力扣
LeetCode
题目
Given a set of distinct positive integers nums
, return the largest subset answer
such that every pair (answer[i], answer[j])
of elements in this subset satisfies:
answer[i] % answer[j] == 0
, oranswer[j] % answer[i] == 0
If there are multiple solutions, return any of them.
Example 1:
Input: nums = [1,2,3]
Output: [1,2]
Explanation: [1,3] is also accepted.
Example 2:
Input: nums = [1,2,4,8]
Output: [1,2,4,8]
Constraints:
1 <= nums.length <= 1000
1 <= nums[i] <= 2 * 10^9
- All the integers in
nums
are unique.
题目大意
给你一个由 无重复 正整数组成的集合 nums
,请你找出并返回其中最大的整除子集 answer
,子集中每一元素对 (answer[i], answer[j])
都应当满足:
answer[i] % answer[j] == 0
,或answer[j] % answer[i] == 0
如果存在多个有效解子集,返回其中任何一个均可。
示例 1:
输入: nums = [1,2,3]
输出:[1,2]
解释:[1,3] 也会被视为正确答案。
示例 2:
输入: nums = [1,2,4,8]
输出:[1,2,4,8]
提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 2 * 10^9
nums
中的所有整数 互不相同
解题思路
排序数组
- 对
nums
进行升序排序,以确保在后续遍历中可以利用整除性质。
- 对
动态规划求解
- 定义
dp[i]
表示以nums[i]
结尾的最大整除子集的长度。 - 通过额外的
parent[i]
数组记录前驱节点索引,从而避免回溯时重复判断整除条件。 - 使用双层循环,遍历
nums
中的每一对元素:- 对于每个
nums[i]
,遍历nums[0]
到nums[i - 1]
,如果满足nums[i] % nums[j] === 0
: - 则更新
dp[i] = max(dp[i], dp[j] + 1)
,表示通过nums[j]
扩展出更长的子集。 - 记录路径
parent[i] = j
,以便回溯生成结果。
- 对于每个
- 定义
回溯构建结果
- 根据
dp
数组找到最大整除子集的终点索引maxIdx
。 - 通过回溯
parent
数组直接生成结果子集。 - 从
parent[maxIdx]
依次回溯,将符合条件的元素加入结果子集。
- 根据
返回结果
- 最后返回子集
res
。
- 最后返回子集
复杂度分析
- 时间复杂度:
O(n^2)
,外层遍历每个元素,内层检查所有前驱节点,形成二重循环。 - 空间复杂度:
O(n)
,需要额外的dp
和parent
数组。
代码
/**
* @param {number[]} nums
* @return {number[]}
*/
var largestDivisibleSubset = function (nums) {
nums.sort((a, b) => a - b);
const n = nums.length;
const dp = new Array(n).fill(1);
const parent = new Array(n).fill(-1); // 记录前驱索引
let maxSize = 1,
maxIdx = 0;
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] % nums[j] == 0 && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
parent[i] = j;
}
}
if (dp[i] > maxSize) {
maxSize = dp[i];
maxIdx = i;
}
}
let res = [];
// 直接通过 parent 数组回溯
for (let i = maxIdx; i >= 0; i = parent[i]) {
res.push(nums[i]);
if (parent[i] == -1) break;
}
return res;
};