77:组合

问题描述

给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。

示例

输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

问题分析

全面做过类似的。只要用回溯法+DFS就能解决。但是纯DFS很慢,我们要控制一下递归深度,对没必要递归下去的趁早结束。这样可以beat 80%的人。

但是我们并不满足于beat 80%的人。我们怎么也要beat 90%吧。
但是,这段代码已经是回溯法的极限了,所以我们要另辟蹊径。

我们也可以用迭代的方式来做这个题目。
我们通过观察,发现结果集有以下特点:
元素都是升序的
元素的最小值是1,最大值是n。
结果集的长度为k。

这是结果集的充要条件。即,我们不用想那么多,我们只需要求出来满足这三个条件的序列即可。

我们能够想到的最简单的结果序列就是1…k.
最简单的最后的结果序列是 n-k…n
然后我们怎么得到下一个序列呢?
根据我们的规则,我们把这个序列变为下一个序列的最小代价就是修改1个元素。修改哪个呢?
1…k,显然修改k为k+1是最符合题意的。问题来了,我们再求下一个序列,怎么做? 是继续修改k+1,还是修改k+1前的值?
这就是我们思考的重点,如果继续修改k+1,是挺简单的,但是会给我们进行下一轮的修改带来麻烦。所以我们用一种投机取巧的方式:

  • 我们每次都修改这个序列中第一个不符合条件的元素。
  • 如果扫描一遍都符合,那么我们就该退出了(因为这时我们已经得到n-k…n了)

AC代码

class Solution:
    def combine(self, n: int, k: int):
        nums = [i for i in range(1,n+1)]
        self.used = [False for i in range(n)]
        self.res = []
        self.solution(nums, [], 0, len(nums), k)
        print(self.res)
        return self.res
    def solution(self,nums,curs,left,right,depth):
        for i in range(left,right):
            if self.used[i] or right - i + len(curs) < depth:
                continue
            curs.append(nums[i])
            self.used[i] = True
            if len(curs) < depth:
                self.solution(nums,curs,i+1,right,depth)
            else:
                self.res.append(curs[:])
            curs.pop()
            self.used[i] = False
s = Solution()
s.combine(5,5)

AC代码2

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        nums = list(range(1, k + 1)) + [n + 1]
        output, j = [], 0
        while j < k:
            output.append(nums[:k])
            j = 0
            while j < k and nums[j + 1] == nums[j] + 1:
                nums[j] = j + 1
                j += 1
            nums[j] += 1
            
        return output
发布了333 篇原创文章 · 获赞 22 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_41687289/article/details/103682709