/* * 368. Largest Divisible Subset * 2016-7-16 by Mingyang * 和LIS很相似,dp[i]表示nums数组从0到i的最大集合的size. * 这题应该分成两个问题:得到最大集合size,输出这个集合 * 对于第一个问题,最大集合size就是dp数组的最大值,可以边画表边维护一个当前最大值; * 对于第二个问题,我们要维护一个parent数组,记录nums[i]加入到了哪个集合; * dp[i] = max(dp[i], dp[j] + 1), where 0<=j<i * 注意这个case: * [1,2,4,8,9,72] * 到72的时候,往前找到9,可以整除,更新dp[5]为max(1, 2 + 1) = 3, * 注意此时应该继续往前找,不能停,直到找到8,发现dp[3] + 1 = 5 > 3,于是更新dp[i] * 注意就是不能停,找到一个能整除并不够,前面有可能有更大的啊~~ * DP的原理就是找到最大的,所以我们不能找到一个整除的就停下来,应该继续寻找,知直到找到最大的 */ public List<Integer> largestDivisibleSubset(int[] nums) { List<Integer> ans = new ArrayList<Integer>(); if (nums.length == 0) return ans; Arrays.sort(nums); int n = nums.length; int[] dp = new int[n], index = new int[n]; Arrays.fill(dp, 1); Arrays.fill(index, -1); int max_index = 0, max_dp = 1; for (int i = 0; i < n; i++) { for (int j = i - 1 ; j >= 0 ; j--) { if (nums[i] % nums[j] == 0 && dp[j] + 1 > dp[i]) { dp[i] = dp[j] + 1; index[i] = j; //index数组就是记录我的前序节点的index,这样最后我只需要一个开头,就可以一直找到最后一个属于一类的节点 } } //不能停,找到最大的就是在后面 if (max_dp < dp[i]) { max_dp = dp[i]; max_index = i; } } for (int i = max_index; i != -1; i = index[i]) ans.add(nums[i]); return ans; }