77组合

题目:给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:输入: n = 4, k = 2输出:[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],]
来源:https://leetcode-cn.com/problems/combinations/

法一:自己的代码  耗时很短,时间上击败了百分之99的代码

思路:关键是剪枝条件的使用,要亲自动手画出树状图进行观察归纳.剪枝的时候要彻底,这就要求归纳出所有的情况.

from typing import List
class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        # 不用这个内存会小点
        # nums = [i+1 for i in range(n)]
        results = []
        def backtrack(a=[],start=0, end=n):
            # 虽然剪枝了,但是不够彻底,这里剪的是:如果a长度加上后面的要遍历的数的个数恰好是k了,
            # 即题目要求的,这个时候就直接返回不再遍历了,但是这样剪枝不够彻底,比如要从1到5选4个不重复的数,
            # 假如先选了1,第二次遍历的数中就不需要选4和5了,因为选也是白选,所以这里就需要剪掉,
            if len(a) + (end - start) == k:
                # print('-' * 20)
                # print(a)
                # print(range(start,n - (k - len(a)) + 1))
                a = a + list(range(start+1, end + 1, 1))
                results.append(a)
                return
            if len(a) == k:
                results.append(a)
                return
            # 事实上每次需要选哪些数进行遍历,是与a的长度密切相关的,这里明确限定了在a的不同长度下,
            # 需要遍历哪些数,大大降低了程序的遍历个数,节省了时间
            # 注意这里的range中的数比实际遍历的数小1,可以看作是索引,所以backtrack中的start要加1
            for i in range(start,n - (k - len(a)) + 1):
                backtrack(a+[i+1], i+1, end)
                ## 这里不需要再判断a的长度,因为a的长度是从1往上递增的,一旦等于k就会return,不会出现大于k的情况,
                # if len(a) < k:
                #     backtrack(a+[i+1], i+1, end)
                # else:
                #     break
        backtrack()
        return results
if __name__ == '__main__':
    duixiang = Solution()
    a = duixiang.combine(5,3)
    print(a)
View Code