【LeetCode/LintCode】Facebook面試題:子集 II
阿新 • • 發佈:2020-09-21
給定一個可能具有重複數字的列表,返回其所有可能的子集。
線上評測地址:
樣例 1:
輸入:[0]
輸出:
[
[],
[0]
]
樣例 2:
輸入:[1,2,2]
輸出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
解題思路
- 這道題我們需要使用dfs+回溯的方法來進行求解。
- 由於題目明確指出列表中可能有重複數字,所以我們在dfs的時候要進行剪枝。
演算法
- 將陣列進行升序排列。
- 定義一個遞迴方法 dfs,引數有:當前子集subset,當前子集長度k,返回結果res。將當前子集新增到
舉例分析
- 假設nums = [1, 2, 2'],遞迴樹如圖所示。樹每深一層,子集的長度就加一。每個節點都是滿足條件的子集,需要記錄到結果res中。
- 其中標叉的地方進行了剪枝。由於陣列中有兩個2,所以如果兩者在同一層,只保留第一個。
複雜度分析
- 時間複雜度:O(n∗2n)O(n∗2n),其中n為nums的長度。生成所有子集,並複製到輸出集合中。
- 空間複雜度:O(n∗2n)O(n∗2n),其中n為nums的長度。儲存所有子集,共 n個元素,每個元素都有可能存在或者不存在。
程式碼
ublic class Solution { /** * @param nums: A set of numbers. * @return: A list of lists. All valid subsets. */ public List<List<Integer>> subsetsWithDup(int[] nums) { List<List<Integer>> res = new ArrayList<>(); // 排序 Arrays.sort(nums); // dfs搜尋 Deque<Integer> subset = new ArrayDeque<>(nums.length); dfs(nums, 0, subset, res); return res; } private void dfs(int[] nums, int k, Deque<Integer> subset, List<List<Integer>> res) { // 當前組合存入res res.add(new ArrayList<>(subset)); // 為subset新增一位元素 for (int i = k; i < nums.length; ++i) { // 剪枝 if (i != k && nums[i] == nums[i - 1]){ continue; } subset.addLast(nums[i]); // 下一層搜尋 dfs(nums, i + 1, subset, res); // 回溯 subset.removeLast(); } } }
更多題解參考: