368. 最大整除子集
思路:
这也是一个比较简单的动态规划题,首先我们需要对数组排序,这样在遍历数组时只需要保持这个nums[i]%nums[j] == 0判断顺序即可。
定义dp[i]为从0开始以i结尾的最长整除子集。但是题目中要求出子集的链表,所以我们需要保存这个路径,因此需要再定义一个数组保存j的上一个节点,这样在确定完最长整除子集的最后一个节点后能根据上一个节点不断推出整个最长子集。
先初始化:
Arrays.sort(nums);
int[] dp = new int[nums.length];
int[] pre = new int[nums.length];
Arrays.fill(pre,-1);//一定要是-1
Arrays.fill(dp,1);
然后遍历数组:
int max = 1;
//int index = -1;
int index = 0;//这里一定要初始化为0,因为当最长长度为1时,index再后续循环中不会被更新,因此开始设置为0,防止最后因为index=-1而输出空的res
for(int i=1;i<nums.length;i++){
for(int j=0;j<i;j++){
if(nums[i]%nums[j] == 0 && dp[j]+1 > dp[i]){
pre[i] = j;
dp[i] = dp[j] + 1;
}
}
if(dp[i] > max){
max = dp[i];
index = i;
}
}
注意:int index = 0 这里一定要初始化为0,因为当最长长度为1时,index再后续循环中不会被更新,因此开始设置为0,防止最后因为index=-1而输出空的res。
最后得到结果集,注意这里的结果集是反的,不过题目也没有要求有序:
for(int i = index;i>=0;){
res.add(nums[i]);
i = pre[i];//当pre[i]=-1时表示当前nums[i]已是最后一个,故退出循环
}
完整代码如下:
public List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> res = new ArrayList<>();
if(nums.length == 0) return res;
// if(nums.length == 1){
// res.add(nums[0]);
// return res;
// }
Arrays.sort(nums);
int[] dp = new int[nums.length];
int[] pre = new int[nums.length];
Arrays.fill(pre,-1);
Arrays.fill(dp,1);
int max = 1;
int index = 0;
for(int i=1;i<nums.length;i++){
for(int j=0;j<i;j++){
if(nums[i]%nums[j] == 0 && dp[j]+1 > dp[i]){
pre[i] = j;
dp[i] = dp[j] + 1;
}
}
if(dp[i] > max){
max = dp[i];
index = i;
}
}
for(int i = index;i>=0;){
res.add(nums[i]);
i = pre[i];
}
return res;
}