0
点赞
收藏
分享

微信扫一扫

算法_回溯_组合问题

Spinach菠菜 2022-02-12 阅读 86

文章目录

组合

leetcode链接

1.解法

首先看到这道题首先想到的是暴力解决,即如果是n个数字组成的集合,选k个的话,我们只需要建立k个for循环依次枚举即可。假设k=2,那么会如下所示:

for (int i = 1; i <= n; i++) {
    for (int j = i + 1; j <= n; j++) {
        cout << i << " " << j << endl;
    }
}

但是如果当k很大或者k没有明确的给出的时候,就像这道题,k是作为一个参数给定的,没有具体的数值,我们就不知道该写几个循环了,因此我们要写一个算法,让他自动帮我们写好k个for循环。

在深入思考一下,这道题不就刚好符合我们说的回溯法的定义,即集合的大小为树的宽度,递归(循环)的深度为树的深度。因此我们可以画出下图:

在这里插入图片描述
对于这道题,如果画成树的形式就会如上图所示。

  1. 首先我们先写出该函数头和一些变量来储存结果:

     result = [] # 用来存放最终结果
     path = [] # 用来存放每条结果
     
     def backtracking(n,k,startindex)
    

    参数的确定是通过分析逻辑来确定的,可以先往下看。

  2. 接着我们来确定递归结束条件

    看上图来讲,就是每当我们取得的数字的个数等于k了,就需要结束该层递归

     if len(path) == k:
     	path1 = path.copy() # 这里注意要copy一下,不然回溯的时候会影响result中的值
     	result.append(path1)
     	return
    
  3. 确定逻辑:

    第一层for循环要遍历[1,2,3,4],第二层for循环要从上一次循环选中的数+1开始进行遍历。举个例子,如果第一层选中了1,那么第二层循环就要从[2,3,4]中选择;如果第一层选中了2,那么第二层循环就要从[3,4]中选择。这和我们上面写的循环也是对应的。

    因此我们可以写出逻辑部分的代码:

     for i in range(startindex,n+1): # 定义一个startindex作为本次循环的开始数值
     	path.append(i)
     	backtracking(n,k,i+1)
     	path.pop()
    
  4. 最终代码为:

     def combine(n, k):
         result = []
         path = []
     
         def backtracking(n,k,startindex):
             if len(path) == k:
                 path1 = path.copy()  # 这里注意要copy一下,不然回溯的时候会影响result中的值
                 result.append(path1)
                 return
     
             for i in range(startindex,n+1):
                 path.append(i)
                 backtracking(n,k,i+1)
                 path.pop()
     
         backtracking(n,k,1)
         return result
    

2.总结

组合问题是回溯中非常经典的问题,需要重点掌握。

举报

相关推荐

0 条评论