LeetCode 368
题目描述:
Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.
If there are multiple solutions, return any subset is fine.
Example 1:
nums: [1,2,3] Result: [1,2] (of course, [1,3] will also be ok)
Example 2:
nums: [1,2,4,8] Result: [1,2,4,8]
思路:动态规划
需要注意到一点,题目要求的是整除,则当nums从小到大排列之后,对于i<j,如果 nums[k]%nums[j]==0 则一定有 nums[k]%nums[i] == 0
如此,该题目只需要维护一个一维数组即可得到结果。不过只是动归的话,仅能得到subset的大小,如果要得到subset的具体值,参照Dijkstra,再维护一个数组以记录last node,最后只需要回溯一下就OK。
AC代码:
1 public int[] sort(int [] nums){ 2 int k, min; 3 for (int i = 0; i< nums.length; i++){ 4 min = Integer.MAX_VALUE; 5 k = 0; 6 for (int j = i; j< nums.length; j++){ 7 if ( min > nums[j]){ 8 min = nums[j]; 9 k = j; 10 } 11 } 12 nums[k] = nums[i]; 13 nums[i] = min; 14 } 15 16 return nums; 17 } 18 19 public List<Integer> largestDivisibleSubset(int[] nums){ 20 if (nums.length <= 0) return new ArrayList<Integer>(); 21 nums = sort(nums); 22 int size = nums.length; 23 int [] times = new int[size]; 24 int [] index = new int[size]; 25 for (int i = 0; i< size; i++){ 26 times[i] = 1; 27 index[i] = -1; 28 } 29 for (int i = 0; i< size; i++){ 30 for (int j = 0; j< i; j++){ 31 if (nums[i]%nums[j] == 0 && times[j] + 1 > times[i]){ 32 times[i] = times[j] + 1; 33 index[i] = j; 34 } 35 } 36 } 37 int k = 0, max = 0; 38 for (int i = 0; i < size; i++){ 39 if (max <= times[i]){ 40 k = i; max = times[i]; 41 } 42 } 43 List<Integer> res = new ArrayList<Integer>(); 44 while(k >= 0){ 45 res.add(nums[k]); 46 k = index[k]; 47 } 48 return res; 49 }
经验&教训:
第一次我不是这样想的,第一次我是想,对于集合{a, b, c, d, e},先判断集合是否满足两两整除,如果不是,则分别考虑5个只有4个元素的子集,分别寻找子集中的最大子集。如此,复杂度为2^n。
主要是没有注意到,如果把集合排序,会有什么样的特性。有序数据真是创造奇迹的存在啊