leetcode每日一题:最大整除子集
题目
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
中的所有整数 互不相同
思路
动态规划的题目,关键在与定义状态和状态转移方程,这2个步骤是要一起考虑的。本题需要绕一个弯,我们可以分成2个子问题:
-
求出最大集合的元素数量
-
求出最大集合的每个元素(有多个符合条件的集合的话,只要求解出其中一个)
求出最大集合的元素数量
我们先对原数组做从小到大排序,定义一个一维数组dp[]
,dp[n]
代表以下标为n的数字作为集合最大元素时,集合的最大size。根据整除子集的定义,我们在求dp[n+1]
的时候,就可以遍历0 ~ n
,如果num[n+1]
可以整除num[j]
,那么dp[n+1]
的1种解是dp[j]+1
,所以dp[n+1] = max(dp[j]+1)
,条件是num[n+1]%num[j]==0
。那如果0~n
任何一个数都不能被整除,那么这个子集只能包含num[n+1]
自己,即dp[n+1] = 1
。最后,我们遍历dp[0] ~ dp[len-1]
,求可以得到最大集合的元素数量max。
求出最大集合的每个元素
这一步是本题比较容易错误的一个点,上述求解最大集合的元素数量的过程,我们可以同时记录下最大集合的结束元素值maxValue
和它的下标maxIndex
。然后从后往前遍历去找它前一个元素,找到后把找到的元素作为maxValue
,下标作为maxIndex
,继续递归,直到找满max个元素即可。这里注意,找到一个可以被maxValue
整数的值之后,不一定就是要找的循环,必须再判断1层dp[i] == maxSize - 1
,否则可以出现错误,我们举个例子: 原数组为:[3,6,8,24]
dp值为:[1,2,1,3]
此时,maxValue = 24,maxIndex = 3
,所以从下标为2开始从后往前找,找到了8是可以被24整除的,但是显然8不是我们结果集合应该有的元素。如果加上判断1层dp[i] == maxSize - 1
,就可以避免这个错误。
图解
代码
/** * 分成2步 * 1、求出最大集合的元素数量 * 2、求出最大集合的每个元素 */ public List<Integer> largestDivisibleSubset(int[] nums) { List<Integer> ans = new ArrayList<>(); int len = nums.length; // 下标i的数作为子集中最大数,dp[i]表示子集的最大大小 // 对于j in [0, i-1],如果nums[i] % nums[j] == 0, dp[i] = max(dp[j]+1) // 如果都无法整除 dp[i] = 1 int[] dp = new int[len]; Arrays.sort(nums); dp[0] = 1; int max = dp[0]; int maxIndex = 0; int maxVal = nums[0]; for (int i = 1; i < len; i++) { int temp = 1; for (int j = 0; j < i; j++) { if (nums[i]%nums[j] == 0 && dp[j] + 1 > temp) { temp = dp[j] + 1; } } dp[i] = temp; if (dp[i] > max) { max = dp[i]; maxIndex = i; maxVal = nums[i]; } } // 回查原数组,找到最大的集合 ans.add(nums[maxIndex]); int maxSize = max; while (ans.size() < max) { for (int i = maxIndex-1; i >= 0; i--) { if (maxVal%nums[i] == 0 && dp[i] == maxSize - 1) { ans.add(nums[i]); maxVal = nums[i]; maxIndex = i; maxSize--; break; } } } return ans; }