回溯——1.组合

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

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

解题思路总结

  • 回溯法是一种非常有效的组合生成策略。它通过在路径中添加元素,并不断递归深入,再回溯撤销操作,确保能够找到所有可能的组合。
  • 优化点在于通过控制循环的范围,避免了不必要的计算,从而提升了算法的效率。通过提前计算可以填入组合的数字范围,代码避免了无效的递归,缩减了计算空间。

完整代码如下:

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        result = []  # 存放结果集
        self.backtracking(n, k, 1, [], result)
        return result
    def backtracking(self, n, k, startIndex, path, result):
        if len(path) == k:
            result.append(path[:])
            return
        for i in range(startIndex, n - (k - len(path)) + 2):  # 优化的地方
            path.append(i)  # 处理节点
            self.backtracking(n, k, i + 1, path, result)
            path.pop()  # 回溯,撤销处理的节点
def combine(self, n: int, k: int) -> List[List[int]]:
    result = []  # 存放结果集
    self.backtracking(n, k, 1, [], result)
    return result
  • combine 方法是程序的入口函数。
  • result 是一个空列表,用来存储所有符合条件的组合结果。
  • 调用了 backtracking 方法来执行递归和回溯操作,从数字 1 开始,逐步构建组合。
def backtracking(self, n, k, startIndex, path, result):
    if len(path) == k:
        result.append(path[:])
        return
    for i in range(startIndex, n - (k - len(path)) + 2):  # 优化的地方
        path.append(i)  # 处理节点
        self.backtracking(n, k, i + 1, path, result)
        path.pop()  # 回溯,撤销处理的节点
  • 递归终止条件:

    • if len(path) == k: 如果当前路径 path 的长度达到了 k,表示已经形成了一个完整的组合。
    • result.append(path[:]): 将当前组合的副本加入到 result 中。
    • return: 结束当前递归。
  • 循环部分:

    • for i in range(startIndex, n - (k - len(path)) + 2): 这是一个循环,用来尝试从 startIndexn 的每一个数字作为组合的一部分。这里的范围设置是一个优化点,确保循环不会无意义地执行。
      • n - (k - len(path)) + 2 确保了剩下的数字足够填满组合。例如,如果 k 是 3,而当前 path 中已经有 2 个数字,那么剩下的空间只能容纳 1 个数字,因此 i 不需要遍历到 n
  • 处理节点:

    • path.append(i): 将当前数字 i 加入到路径 path 中。
  • 递归调用:

    • self.backtracking(n, k, i + 1, path, result): 递归地处理下一个数字,startIndex 更新为 i + 1,表示下一个组合元素只能从 i 之后的数字中选取。
  • 回溯:

    • path.pop(): 在递归返回后,将当前数字 i 从路径 path 中移除,恢复到递归前的状态,进行下一轮循环。这一步是“回溯”的核心操作。

你可能感兴趣的:(算法)