题目
题目地址 :https://leetcode.com/problems/largest-divisible-subset/
题意解析
给定一个数组,这个数组数唯一且为正数,求在这个数组中,满足能整除的最大集合。
求解
很自然地想到用动态规划,因为满足重叠子问题和最优子结构
重叠子问题:整个数组的最大集合,可以认为是多个子问题组成的
最优子结构:反证法,显而易见。
定义最优解:最大集合是什么。
定义最优解的值:最大集合有多少个数。
定义 f[i]表示从0到i最大能整除集合里的个数。
递归式求解最优解的值:
f[i]= max{f[i],f[j]+1} if nums[i]%nums[j]==0
其中 j从i-1 downto 0
初始化条件:对于每个f[i],至少有i%i ==0;定义为1;
根据题意需要记录集合的内容,故需要记录每一步执行的index
Code
ac代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Created by loveqh on 2016/8/13.
*/
public class LargestDivisibleSet {
public List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> result = new ArrayList<Integer>();
Arrays.sort(nums);
int[] f = new int[nums.length];
int[] pre = new int[nums.length];
int max = -1;
int index = -1;
//初始化f 和前导
for (int i = 0; i < f.length; i++) {
f[i] = 1;
pre[i] = -1;
}
if (nums.length == 1) {
result.add(nums[0]);
return result;
}
for (int i = 1; i < nums.length; i++) {
//一轮循环,找到从0到i的可整除集合的长度
for (int j = i - 1; j >= 0; j--) {
if (nums[i] % nums[j] == 0 && (f[i] < f[j] + 1)) {
f[i] = f[j] + 1;
//记录i的前导
pre[i] = j;
}
}
//relax max的值
if (max < f[i]) {
max = f[i];
index = i;
}
}
if (index != -1) {
result.add(nums[index]);
}
while (index > 0) {
if (pre[index]!=-1){
result.add(nums[pre[index]]);
index = pre[index];
}else {
break;
}
}
//求得的result为逆序的,应该转化为开始的样子
Collections.reverse(result);
return result;
}
public static void main(String[] args) {
int[] a = {546,669};
List<Integer> res = new LargestDivisibleSet().largestDivisibleSubset(a);
for (Integer value : res) {
System.out.print(value + " ");
}
}
}