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 中的所有整数 互不相同

 

解题思路

我一开始感觉这题跟最长上升子序列差不多,也是每次考虑以当前第i个数作为结尾时,都要往回看,即回溯到最前面,更新当前的状态,而且这里还需要的就是让当前第i个数跟前面每个数所在的子集都比较一遍,这样才能选出最大的那个,因为我用的是动规来做,f[i]表示的就是以第i个数结尾的整除子集,当算完所有结尾的数的子集后,最后的答案就是从这些结尾的整除子集中选出最大的那个子集来,由于题目已经明确说明了,如果存在多个有效子集,返回其中任何一个均可。这题刚开始以为不排序就可以,可是当前测试我前面的思路时,答案总是错误,最后还是给数组排了序,没想到还真出来了,虽然还是没弄清为啥排序之后就能保证正确性,希望有大佬指点一二,小弟不胜感激!!!

后来醒悟

原来没有排序的话,会有一种情况得出的答案是错误的,例如:输入[3, 27, 9, 18, 36] 如果按照我一开始没有排序的代码,那么每个数对应的子集应该是{3}、{3, 27}、{3, 27, 9}、{3, 18}、{3, 18, 36},最后返回的最大整除子集就会是{3,18,36},而实际上应该是{3, 9, 1, 36}长度为4,而不是长度为3的子集{3,18,36},这一点是真的难想到,经过这一题的教训,以后做题要多考虑边界情况,不然连自己都找不出代码到底错在哪,这题其实是跟数学相关,对数学中数字比较敏感的话,这个反例应该很容易就会想得到,所以说算法是程序的灵魂,数学是算法的基础,这句话是有一定道理的(哎,都怪以前数学没有认真学,对数字的敏感度也不是很强)。

 

AC代码

 1 class Solution {
 2     public List<Integer> largestDivisibleSubset(int[] nums) {
 3         int n = nums.length;
 4         if (n == 1) {
 5             List<Integer> list = new ArrayList<>();
 6             list.add(nums[0]);
 7             return list;
 8         }
 9 
10         // 排序,这一点很重要
11         Arrays.sort(nums);
12 
13         // 存储以i结尾的最大整除子集中的每个元素
14         List<Integer>[] list = new ArrayList[n + 1];
15         for (int i = 1; i <= n; i++) {
16             list[i] = new ArrayList<>();
17         }
18 
19         int[] f = new int[n + 1];
20         f[0] = 0;
21         f[1] = 1;
22 
23         list[1].add(nums[0]);
24 
25         for (int i = 2; i <= n; i++) {
26             f[i] = 1;
27             list[i].add(nums[i - 1]);
28             int index = i;
29             for (int j = 1; j < i; j++) {
30                 boolean flag = true;
31                 for (int k = 0; k < list[j].size(); k++) {
32                     if (nums[i - 1] % list[j].get(k) != 0 && list[j].get(k) % nums[i - 1]                       != 0) {
33                         flag = false;
34                         break;
35                     }
36                 }
37                 if (flag && f[j] + 1 > f[i]) {
38                     // 更新
39                     f[i] = f[j] + 1;
40                     index = j;
41                 } 
42             }
43             // 这里需要做个判断,不然就会加入重复的数到集合中去
44             if (index != i) {
45                 list[i].addAll(list[index]);
46             }
47             
48         }
49     
50         int res = 1;
51         int index = 1;
52         for (int i = 1; i <= n; i++) {
53             if (list[i].size() > res) {
54                 res = list[i].size();
55                 index = i;
56             }
57         }
58         
59         return list[index];
60     }
61 }

力扣链接:https://leetcode-cn.com/problems/largest-divisible-subset/comments/

posted @ 2021-04-23 23:51  没有你哪有我  阅读(95)  评论(0编辑  收藏  举报