leetcode368—最大整除子集原题链接
题意简述
给出一个由无重复的正整数组成的集合,找出其中最大的整除子集,子集中任意一对 (Si,Sj) 都要满足:Si % Sj = 0 或 Sj % Si = 0.
如果有多个目标子集,返回其中任何一个均可。
示例 1:
输入: [1,2,3]
输出: [1,2] (当然, [1,3] 也正确)
示例 2:
输入: [1,2,4,8]
输出: [1,2,4,8]
解题分析
约定函数接口: List<Integer> largestDivisibleSubset(int[] nums)
预处理: 对nums进行升序排序
dp[i]: 表示以nums[i]为最大元素的整除子集的最大长度
状态转移方程:
显然,
dp[i]=max(dp[i],dp[j]+1),(0<=j<i && nums[i]%nums[j]==0).
初始状态:
dp[i]=1;
复杂度分析:
时间复杂度: O(n2);
空间复杂度: O(n)
Plus: 本题还要求求出具体的集合,将dp过程记忆化便可.
pre[i]: 表示以nums[i]为最大元素的最大整除子集第二大元素在nums数组的索引.
参考代码
class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> ans = new ArrayList<Integer>();
if(nums.length == 0) return ans;
int[] dp = new int[nums.length];
int[] pre = new int[nums.length];
int maxx = 0;
int idx = -1;
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++) {
dp[i] = 1;
pre[i] = -1;
}
maxx = 1;
idx = 0;
for(int i = 0; i < nums.length; i++) {
for(int j = 0; j < i; j++) {
if(nums[i] % nums[j] == 0 && dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
pre[i] = j;
if(maxx < dp[i]) {
maxx = dp[i];
idx = i;
}
}
}
}
while(idx != -1) {
ans.add(nums[idx]);
idx = pre[idx];
}
return ans;
}
}
func largestDivisibleSubset(nums []int) []int {
length := len(nums)
ans := make([]int,length)
if length == 0 {
return ans[0:0]
}
dp := make([]int,length)
pre := make([]int,length)
sort.Ints(nums)
for i := 0; i < length; i++ {
dp[i] = 1
pre[i] = -1
}
maxx := 1
idx := 0
for i := 1; i < length; i++ {
for j := 0; j < i; j++ {
if nums[i] % nums[j] == 0 && dp[j] + 1 > dp[i] {
dp[i] = dp[j] + 1
pre[i] = j
if maxx < dp[i] {
maxx = dp[i]
idx = i
}
}
}
}
count := 0
for idx != -1 {
ans[count] = nums[idx]
idx = pre[idx]
count++
}
return ans[:count]
}