368. 最大整除子集(序列dp)
Posted mp-ui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了368. 最大整除子集(序列dp)相关的知识,希望对你有一定的参考价值。
368. 最大整除子集
题目描述
368. 最大整除子集
给你一个由 无重复 正整数组成的集合 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 * 109
nums 中的所有整数 互不相同
通过次数35,218提交次数77,473
题解
参考题目:300. 最长递增子序列
这道题目可以采用动态规划来解。相当于最长递增子序列的解法,我们假定dp[i]
代表以 nums[i]
为结尾的最大整除子集的元素个数,解答过程和最长递增子序列的类似,最长递增子序列这道题的if判断那里是nums[i] > nums[j]
,而这里是nums[i] % nums[j] == 0
最后,我们就可以轻而易举地求解出最大整除子集的元素个数,但是题目并不是要求我们求出长度,而是求出长度最长的那个List
所以,为了方便求出路径,我们使用数组g
来记录,定义g[i]
为最大整除子集中nums[i]
的上一个元素在nums
数组对应的下标。
最后通过回溯来求就行了(这里就像是用BFS求迷宫最短路径,也是需要用一个数组来记录)
代码如下:
class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
Arrays.sort(nums); //【踩坑!!!】需要排序一下
int n = nums.length;
//类似题目:300. 最长递增子序列
int[] dp = new int[n]; //dp[i]:以nums[i]结尾的最大整除解集的元素个数
int[] g = new int[n]; //g[i]:nums[i]的上一个
for (int i = 0; i < n; i++) {
dp[i] = 1;
g[i] = -1;
for (int j = i - 1; j >= 0; j--) {
if(nums[i] % nums[j] == 0){
//能整除
if(dp[i] < dp[j] + 1){
dp[i] = dp[j] + 1;
g[i] = j; //表示nums[i]的上一个是nums[j]
}
}
}
}
//遍历dp,找到最大的那个
int maxI = 0; //记录最大值的下标
int maxV = dp[0]; //记录最大值
for (int i = 0; i < dp.length; i++) {
if(dp[i] > maxV){
maxI = i;
maxV = dp[i];
}
}
//获取到最大的之后,通过回溯g数组来获得最大整除子集
LinkedList<Integer> res = new LinkedList<>();
int times = 0; //记录次数
int now = maxI; //当前下标
while(times < maxV && now != -1){
//最长子集里面有maxV个数,所以回溯maxV次
res.addFirst(nums[now]);
now = g[now];
++times;
}
return res;
}
}
运行结果:
以上是关于368. 最大整除子集(序列dp)的主要内容,如果未能解决你的问题,请参考以下文章