# 第76期-基础算法:回溯 组合

Python是一门需要不断实践练习的编程语言,本文档将AI大学堂学员交流群的Python每周练习进行汇总,希望各位小伙伴能够多进行实践练习,逐渐爱上这门神奇的编程语言,掌握它并在生活中能够使用它。

# 1 问题描述

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。

示例 1:

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

输入: n = 1, k = 1
输出: [[1]]

初始代码

from typing import List
class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        #在此之间填写代码

print(Solution().combine(4,2))
print(Solution().combine(1,1))
1
2
3
4
5
6
7

# 2 解题思路

  • 标签:回溯
  • 如果解决一个问题有多个步骤,每一个步骤有多种方法,题目又要我们找出所有的方法,可以使用回溯算法;
  • 回溯算法是在一棵树上的 深度优先遍历(因为要找所有的解,所以需要遍历);
  • 组合问题,相对于排列问题而言,不计较一个组合内元素的顺序性(即 [1, 2, 3] 与 [1, 3, 2] 认为是同一个组合),因此很多时候需要按某种顺序展开搜索,这样才能做到不重不漏。

# 3 解题方法

from typing import List
class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        res,path=[],[]
        m=list(range(1,n+1))
        def backtrack(a,res,path,k):
            if k==0:
                res.append(path[:])
            x=len(a)
            for i in range(x):
                b=a.pop(i)
                path.append(b)
                backtrack(a[i:],res,path,k-1)
                path.pop()
                a.insert(i,b)
        backtrack(m,res,path,k)
        return res

print(Solution().combine(4,2))
print(Solution().combine(1,1))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

第1-3,19-20行: 题目中已经给出的信息,运行代码时要根据这些代码进行编辑
第4行: 定义列表res、path分别用于存放每个组合和组合中的数字
第5行: 定义变量m并赋值从1到n的列表
第6行: 创建backtrack回溯函数,内部变量初始列表以及后面要求的列表以及限制条件
第7-8行: 当k=0时,说明此时path里面元素的数量已经满足条件了,将其放进res列表中
第9-10行: 定义变量x用于存放初始列表长度用于之后的for循环遍历列表元素
第11行: 定义变量b,从初始列表中删除第一个元素并赋值给b
第12行: 在path列表中添加该元素
第13行: 使用backtrack函数对剩余的列表进行相同操作
第14-15行: 回溯操作的回溯,返回
第9-10行: 定义变量x用于存放初始列表长度用于之后的for循环遍历列表元素
第11行: 定义变量b,从初始列表中删除第一个元素并赋值给b
第12行: 在path列表中添加该元素
第13行: 使用backtrack函数对剩余的列表进行相同操作
第14-15行: 回溯操作的回溯,返回迭代之前的元素,对下一个元素进行操作
第16行: 函数定义完成,开始运行函数
第17行: 返回最后的res

代码运行结果为:
image.jpg

# 算法讲解

这里用到了基础算法:回溯,简单讲解下这个算法:
回溯
回溯是很经典的一个算法,什么是回溯,回溯其实是一种暴力枚举的方式,为啥都暴力了还是很经典的一种方法呢,其实是因为有些问题我们能暴力出来就不错了,就别要其他自行车了。常见的回溯类问题:组合;排列;切割;子集;棋牌;
其实回溯算法就是常说的DFS,本质上是一种暴力枚举算法;
回溯算法常用于解决的问题:
组合
排列
切割
子集
棋盘:N皇后

比如最经典的排列。从1,2,3,4,5中取3个数组成排列有多少种,我们肯定会解决这种问题,但是程序怎么写呢。想一下我们解决这个问题的过程,我们先选1,然后第二个数可以选2,第三个数可以选3,这是一种答案了,然后呢,换第三个数,第三个数选4,又一种答案,再换,第三个数选5,没得选了,所以以12打头的数都选完了,得到三种答案.然后再换第二个数,第二个数选3,然后第三个数选4,注意是组合问题所以我们不能退往回选2了,不然就重复了。就是这样一种选择方案,一直到第3个数选成了3,得到答案345,就不用往后进行了。

# 4 视频解析

高清视频讲解,请查看AI大学堂Python基础实战100例 (opens new window)
关注『讯飞AI大学堂』公众号,发送 python100 即可领取Python基础实战100例源代码
AI大学堂公众号.png

更新于: 12/28/2021, 7:43:14 AM