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:
Input: [1,2,3]
Output: [1,2] (of course, [1,3] will also be ok)
Example 2:
Input: [1,2,4,8]
Output: [1,2,4,8]
題目大意:給定一個無重複的正整數集合,找出最大的整除子集。子集中任意一對($S_i$, $S_j$)都滿足: $S_i \% S_j = 0$ 或 $S_i \% S_j = 0$。
如果有多個子集符合條件,返回其中一個即可。
基本思路:列出集合所有的子集,共有$2^n$個,再進行判斷,時間複雜度為O($C_n^2 \times 2^n$),其中$n$為集合元素個數。
由於返回的子集需要滿足子集中任意一對($S_i$, $S_j$)有 $S_i \% S_j = 0$ 或 $S_i \% S_j = 0$,為了減少考慮次數,可以考慮先對原始集合排序,這樣只要考慮$S_i \% S_j$(i > j)。
排好序之後的做法基本和最長遞增子序列(https://leetcode.com/problems/longest-increasing-subsequence/)一致。
做法: 1、對集合陣列nums排序,長度為len=nums.size();
2、定義一個和nums等長的陣列dp[len], 其中dp[i]表示nums[0,..., i]符合條件的最大子集的長度。dp[j] = max(dp[i]) + 1 (i = 0, 1, ..., j - 1. 且nums[j] % nums[i] = 0)。初始化為1.
3、定義一個和nums等長的索引陣列index[len]。index[i]表示以nums[i]結尾的滿足條件的最大子集,子集元素nums[i]的前一個元素在原陣列中的索引(下標)。初始化為-1.
4、根據dp陣列,知道滿足條件的最大子集的最後一個元素的索引(下標),然後根據index陣列,推出前面所有的元素。
注:這種做法可以求出所有滿足條件的最大子集。
C++程式碼:
1 class Solution { 2 public: 3 vector<int> largestDivisibleSubset(vector<int>& nums) { 4 int len = nums.size(); 5 if (len == 0) //陣列長度為0,直接返回空集。 6 return {}; 7 vector<int> dp(len, 1); 8 vector<int> previous_index(len, -1); 9 int max_ind = 0; //記錄最長子集的末尾元素索引值 10 sort(nums.begin(), nums.end()); //按照從小到大排序 11 for (int i = 1; i < len; ++i) { //外層迴圈控制以i結尾的陣列 12 for (int j = 0; j < i; ++j) { //內層迴圈計算dp[i] 13 if ((nums[i] % nums[j] == 0) && (dp[j] >= dp[i])) { 14 dp[i] = dp[j] + 1; 15 previous_index[i] = j; 16 } 17 } 18 if (dp[i] > dp[max_ind]) { 19 max_ind = i; 20 } 21 } 22 vector<int> answer(dp[max_ind], 0); //dp[max_ind]即為最長子集的長度 23 for (int t = max_ind, i = 0; t >= 0; ++i) { 24 answer[i] = nums[t]; 25 t = previous_index[t]; 26 } 27 return answer; 28 } 29 };
時間複雜度:$O(nlogn) + O(n^2)$