[LeetCode题解]216. 组合总和 III
前言
看完这篇题解,可以再看看这几个问题:
题目描述
解题思路
本题与 39. 组合总和、40. 组合总和 II 类似,解法一样,主要区别在于剪枝或去重的条件上。
[39. 组合总和]
剪枝:target-candidates[i] < 0
表示结果集加上 candidates[i]
将超过 target
,不符合条件,剪掉。
[40. 组合总和 II]
剪枝条件与上一题一样,主要是去重的条件:i > start && candidates[i] == candidates[i-1]
[216. 组合总和 III]
剪枝条件有两个情况,一种跟上两题相同:n - i < 0
;另一种是:k == 1 && n-i > 0
。
算法步骤:
- 排序。方便进行剪枝判断。
- 回溯。排列、组合类题目常用方法。
- 剪枝。提前去掉不符合的结果,降低时间复杂度。
- 去重。
代码实现
var ans [][]int // 结果集
var list []int // 临时结果集
func combinationSum3(k int, n int) [][]int {
/*
回溯 + 剪枝 + 去重
剪枝条件: > k 去掉
去重条件: 加 start 控制
*/
ans = make([][]int, 0)
list = make([]int, 0)
backtarck(k, n, 1)
return ans
}
func backtarck(k int, n int, start int) {
if n == 0 && k == 0 {
tmp := make([]int, len(list))
copy(tmp, list)
ans = append(ans, tmp)
return
}
for i:=start;i<=9;i++ {
if n - i < 0 {
break
}
if k == 1 && n-i > 0 {
continue
}
list = append(list, i)
backtarck(k-1, n-i, i+1)
list = list[:len(list)-1]
}
}
复杂度分析:
- 时间复杂度:\(O(2^n * n)\)。一般的递归树的时间复杂度是 \(O(2^n)\),遍历
n
的时间复杂度是 \(O(n)\) ,最终时间复杂度为 \(O(2^n * n)\)。 - 空间复杂度:\(O(n)\)。除了保存结果的数组外,还需要一个数组保存回溯过程的中间结果。