Solution 1
整体来看就是DFS,和之前做到的组合数还不太一样,每个数字能且只能使用一次,因此枚举过程中序列长度也要作为一个终止条件考察。
我只想到了递归做法,非递归做法需要进行选择状态的维护,比较麻烦,就先不考虑实现了。
官方题解还提到了一个额外的剪枝:如果此时最大序列也达不到K长度,提前停止。
官方题解中给出了一个非递归字典序枚举思路,因为我没有想清楚字典序枚举的具体规律,就不实现了。
- 时间复杂度: O ( ( n k ) × k ) O(\binom{n}{k} \times k) O((kn)×k),所有 ( n k ) \binom{n}{k} (kn)中情形,每种需要k长度规模的遍历
- 空间复杂度: O ( n ) O(n) O(n),temp数组最大占用为k,但是递归占用可能会达到n
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> ans;
vector<int> temp;
dfs(1, n, k, temp, ans);
return ans;
}
private:
void dfs(int pos, int n, int k, vector<int> & temp, vector<vector<int>> & ans) {
if (temp.size() + (n - pos + 1) < k) {
// 剪枝,提前终止
return;
}
if (temp.size() == k) {
ans.emplace_back(temp);
return;
}
if (pos == n + 1) {
// 枚举到了结尾,但是还是不够
return;
}
temp.emplace_back(pos);
dfs(pos + 1, n, k, temp, ans);
temp.pop_back();
dfs(pos + 1, n, k, temp, ans);
}
};
Solution 2
Solution 1的Python实现,注意Python的引用特性的处理。
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
ans = []
temp = []
self._dfs(1, n, k, temp, ans)
return ans
def _dfs(self, pos: int, n: int, k:int, temp: List[int], ans: List[List[int]]) -> None:
if len(temp) + (n - pos + 1) < k:
return
if len(temp) == k:
ans.append(copy.deepcopy(temp))
return
temp.append(pos)
self._dfs(pos + 1, n, k, temp, ans)
temp.pop()
self._dfs(pos + 1, n, k, temp, ans)