給定一個無重複元素的整數數組 nums,返回所有可能的子集(冪集)。子集內元素非降序,解集無重複。
示例:nums = [1,2,3] → [[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
n 個元素共有 2^n 個子集。整數 0 ~ 2^n-1 的二進制位完美對應「選/不選」:
public List> subsets(int[] nums) {
List> res = new ArrayList<>();
int n = nums.length;
for (int mask = 0; mask < (1< subset = new ArrayList<>();
for (int i = 0; i < n; ++i)
if ((mask & (1<
Arrays.sort(nums)。public List> subsets(int[] nums) {
Arrays.sort(nums);
List> res = new ArrayList<>();
backtrack(nums, 0, new ArrayList<>(), res);
return res;
}
void backtrack(int[] nums, int start, List path, List> res) {
res.add(new ArrayList<>(path));
for (int i = start; i < nums.length; ++i) {
path.add(nums[i]);
backtrack(nums, i+1, path, res);
path.remove(path.size()-1);
}
}
遞歸樹清晰展示「選/不選」決策,易於擴展到組合總和、排列等問題。
public List> subsets(int[] nums) {
List> res = new ArrayList<>();
res.add(new ArrayList<>());
for (int num : nums) {
int size = res.size();
for (int i = 0; i < size; ++i) {
List cur = new ArrayList<>(res.get(i));
cur.add(num);
res.add(cur);
}
}
return res;
}
每輪將新元素加入現有所有子集,生成新子集。無遞歸棧開銷。
| 維度 | 位掩碼 | 回溯 | 迭代 |
|---|---|---|---|
| 思維直觀度 | ★★★ | ★★☆ | ★★☆ |
| 代碼簡潔度 | ★★★ | ★★☆ | ★★★ |
| 擴展性 | 差 | 強(易加剪枝) | 中 |
| 空間(輔助) | O(1) | O(n) | O(1) |
Subsets I 是子集問題的入門題。位掩碼適合快速寫出正確解;回溯是面試標準解法,便於舉一反三;迭代空間效率最高。建議三種都會寫,並理解它們本質上都是遍歷 {0,1}^n 空間。