Files
2021-04-24 21:04:28 +08:00

86 lines
3.0 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [368. Largest Divisible Subset](https://leetcode.com/problems/largest-divisible-subset/)
## 题目
Given a set of **distinct** positive integers `nums`, return the largest subset `answer` such that every pair `(answer[i], answer[j])` of elements in this subset satisfies:
- `answer[i] % answer[j] == 0`, or
- `answer[j] % answer[i] == 0`
If there are multiple solutions, return any of them.
**Example 1:**
```
Input: nums = [1,2,3]
Output: [1,2]
Explanation: [1,3] is also accepted.
```
**Example 2:**
```
Input: nums = [1,2,4,8]
Output: [1,2,4,8]
```
**Constraints:**
- `1 <= nums.length <= 1000`
- `1 <= nums[i] <= 2 * 109`
- All the integers in `nums` are **unique**.
## 题目大意
给你一个由 无重复 正整数组成的集合 nums ,请你找出并返回其中最大的整除子集 answer ,子集中每一元素对 (answer[i], answer[j]) 都应当满足:
- answer[i] % answer[j] == 0 ,或
- answer[j] % answer[i] == 0
如果存在多个有效解子集,返回其中任何一个均可。
## 解题思路
- 根据题目数据规模 1000可以估计此题大概率是动态规划并且时间复杂度是 O(n^2)。先将集合排序,以某一个小的数作为基准,不断的选择能整除的数加入集合。按照这个思路考虑,此题和第 300 题经典的 LIS 解题思路一致。只不过 LIS 每次选择更大的数,此题除了选择更大的数,只不过多了一个判断,这个更大的数能否整除当前集合里面的所有元素。按照此法一定可以找出最大的集合。
- 剩下的问题是如何输出最大集合。这道题的集合具有重叠子集的性质,例如 [2,4,8,16] 这个集合,长度是 4它一定包含长度为 3 的子集,因为从它里面随便取 3 个数形成的子集也满足元素相互能整除的条件。同理,它也一定包含长度为 2长度为 1 的子集。由于有这个性质,可以利用 dp 数组里面的数据,输出最大集合。例如,[2,4,6,8,9,13,16,40],由动态规划可以找到最大集合是 [2,4,8,16]。长度为 4 的找到了,再找长度为 3 的,[2,4,8][2,4,40]。在最大集合中,最大元素是 16所以 [2,4,40] 这个集合排除,它的最大元素大于 16。选定 [2,4,8] 这个集合,此时最大元素是 8 。以此类推,筛选到最后,便可以输出 [16,8,4,2] 这个组最大集合的答案了。
## 代码
```go
package leetcode
import "sort"
func largestDivisibleSubset(nums []int) []int {
sort.Ints(nums)
dp, res := make([]int, len(nums)), []int{}
for i := range dp {
dp[i] = 1
}
maxSize, maxVal := 1, 1
for i := 1; i < len(nums); i++ {
for j, v := range nums[:i] {
if nums[i]%v == 0 && dp[j]+1 > dp[i] {
dp[i] = dp[j] + 1
}
}
if dp[i] > maxSize {
maxSize, maxVal = dp[i], nums[i]
}
}
if maxSize == 1 {
return []int{nums[0]}
}
for i := len(nums) - 1; i >= 0 && maxSize > 0; i-- {
if dp[i] == maxSize && maxVal%nums[i] == 0 {
res = append(res, nums[i])
maxVal = nums[i]
maxSize--
}
}
return res
}
```