先对数组排序,然后就很像最长上升子序列了,dp[i]就表示以nums[i]结尾的最大整除子集。
转移方程:dp[i] = max{ dp[j] + 1} (0 <= j < i 且 A[j]%A[i] == 0)
初始化:dp[i] = 1 (0 <= i < nums.length),另设路径数组path,用来记录回溯的路线。
目标:max{dp[i]} ( 0 <= i < = N)
时间复杂度:O(n^2)
空间复杂度:O(n)
class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int[] path = new int[n];
//初始化
Arrays.fill(dp, 1);
Arrays.fill(path, -1);
Arrays.sort(nums); //排序时间复杂度O(nlogn)
//dp
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] % nums[j] == 0 && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
path[i] = j; // 下标为i的元素是从j来的
}
}
}
//找出dp最大的下标,作为回溯起始位置
int maxindex = -1;
int max = 0;
for (int i = 0; i < n; i++) {
if (dp[i] > max) {
max = dp[i];
maxindex = i;
}
}
List<Integer> res = new ArrayList<>();
if(maxindex == -1)
return res;
//回溯路线
res.add(nums[maxindex]);
while(path[maxindex] != -1) {
res.add(0,nums[path[maxindex]]);
maxindex = path[maxindex];
}
return res;
}
}
这个题是否可以像LIS那样优化为O(nlogn)呢?我认为不可以,因为遍历到的nums[i],并不是只依赖dp,还要看nums[i]是否能整除前面的每一个元素。
如果所说有误,还请指正,附上LIS的优化版本