leetcode(力扣) 216. 组合总和 III(回溯 & 剪枝)

文章目录

  • 题目描述
  • 思路分析
  • 完整代码
  • 优化(剪枝)

题目描述

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
只使用数字1到9
每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。

示例 3:
输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。

思路分析

这道题跟上一题组合差不多,只是多加了个条件。
建议先做上一个题,上一个题里说过的思路我这就不写了。

继续,回溯三步走:

1. 确定回溯函数条件:

这个就比较容易了,题目所给的n和k肯定得有,然后还得有我们目前所得到的数之和sum,还得有一个记录下标的变量值startindex。startindex是啥,看上一个题。

这次的题目和上一次的有所不同,上一个题给的n是从1到n个数遍历,组合为k个数。
而这道是固定1到9进行遍历,组合为k个数,另加条件为该k个数和为n,所以为了避免混淆,将n的参数定位targetsum。

def backtrack(targetsum,k,startindex,sum):

2.确定终止条件

终止条件就很简单了,如果temp里的个数等于题目所给,则终止,在此之前若temp里的和等于题目所给的值,则先记录到答案集合再终止。

if k == len(temp):
   if sum == targetsum:
        res.append(temp[:])
   return

3.确定循环体

还是利用模板的思路,回调函数之前是本层到下一层要操作的代码,回调函数之后是下一层回到本层要操作的代码。
不用多说,一看就懂。

		for i in range(startindex,10):
                temp.append(i)
                sum +=i
                backtrack(targetsum,k,i+1,sum)
                temp.pop()
                sum -=i

完整代码

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        res = []  # 存结果
        temp = [] # 存路径过程中的数值
        def backtrack(targetsum,k,startindex,sum):
            # 终止条件
            if k == len(temp):
                if sum == targetsum:
                    res.append(temp[:])
                return
            for i in range(startindex,10):
                temp.append(i)
                sum +=i
                backtrack(targetsum,k,i+1,sum)
                temp.pop()
                sum -=i
        backtrack(n,k,1,0)
        return res
        

优化(剪枝)

第一个可以剪的地方,如果当前temp里的和已经大于目标值了,其实就可以直接return了,即使temp里的个数还没达到k个。

第二个可以剪的地方,就是i的最大遍历起始位置,这一点在上一题中也详细的说过了,这里就不说了,公式: 9 - (k - len(temp)) + 1 + 1

剪枝后的完整代码:

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:     
            #带剪枝
            res = []  # 存结果
            temp = []  # 存路径过程中的值

            def backtrack(target_sum, k, sum, startindex):
                # 终止条件
                if sum > target_sum:  # 剪枝
                    return
                if len(temp) == k:
                    if sum == target_sum:
                        res.append(temp[:])
                # 循环体
                for i in range(startindex, 9 - (k - len(temp)) + 1 + 1):  # 剪枝
                    temp.append(i)
                    sum += i
                    backtrack(target_sum, k, sum, i + 1)
                    temp.pop()
                    sum -= i

            backtrack(n, k, 0, 1)
            return res

你可能感兴趣的:(交流学习,个人笔记,1024程序员节,python,leetcode)