給定一個可能包含重複元素的整數集合 S,要求返回所有可能的子集(冪集)。解集不能包含重複的子集,且每個子集內的元素必須按非遞減順序排列。
範例: 若 S = [1,2,2],一個解為:
[ [2], [1], [1,2,2], [2,2], [1,2], [] ]
此題與 LeetCode 78. 子集 唯一的區別在於輸入數組包含重複元素。解決重複子集問題的關鍵在於排序 + 剪枝:
class Solution {
public:
vector> subsetsWithDup(vector& S) {
sort(S.begin(), S.end()); // 關鍵步驟:排序
vector> result;
vector path;
result.push_back(path); // 空集
for (int k = 1; k <= S.size(); ++k) {
dfs(S, k, 0, path, result);
}
return result;
}
private:
void dfs(const vector& S, int k, int start, vector& path, vector>& result) {
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = start; i < S.size(); ++i) {
// 去重核心邏輯:同層遞歸中跳過相同元素
if (i != start && S[i] == S[i-1]) continue;
path.push_back(S[i]);
dfs(S, k, i + 1, path, result);
path.pop_back();
}
}
};
去重條件 `if (i != start && S[i] == S[i-1])` 是精髓所在。`i != start` 確保我們只在「同一層遞歸的橫向遍歷」中跳過重複元素,而允許在「縱向遞歸深入」時選擇相同元素(如選取兩個 2 組成 [2,2])。