代码随想录二刷 |回溯 | 组合

代码随想录二刷 |回溯 | 组合

题目描述

77.组合

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

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

解题思路

递归来做层叠嵌套(可以理解是开k层for循环),每一次的递归中嵌套一个for循环,那么递归就可以用于解决多层嵌套循环的问题了。

此时递归的层数大家应该知道了,例如:n为100,k为50的情况下,就是递归50层。

把组合问题抽象为如下树形结构:
在这里插入图片描述
可以看出这棵树,一开始集合是 1,2,3,4, 从左向右取数,取过的数,不再重复取。

第一次取1,集合变为2,3,4 ,因为k为2,我们只需要再取一个数就可以了,分别取2,3,4,得到集合[1,2] [1,3] [1,4],以此类推。

每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围。

图中可以发现n相当于树的宽度,k相当于树的深度。

图中每次搜索到了叶子节点,我们就找到了一个结果。

相当于只需要把达到叶子节点的结果收集起来,就可以求得 n 个数中 k 个数的组合集合。

回溯法三部曲:

  • 递归函数的返回值和参数
    定义两个全局变量,一个用来存放符合条件的单一结果,另一个存放符合条件结果的集合

    vector<vector<int>> result; // 存放符合条件结果的集合
    vector<int> path; // 用来存放符合条件结果
    

    函数里一定有两个参数,既然是集合n里面取k个数,那么n和k是两个int型的参数。

    然后还需要一个参数,为int型变量startIndex,这个参数用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,…,n] )。

    从下图中红线部分可以看出,在集合[1,2,3,4]取1之后,下一层递归,就要在[2,3,4]中取数了,那么下一层递归如何知道从[2,3,4]中取数呢,靠的就是startIndex。
    在这里插入图片描述
    所以需要startIndex来记录下一层递归,搜索的起始位置。

vector<vector<int>> result;
vector<int> path;
void backtracking(int n, int k, int startIndex);
  • 递归函数的终止条件
    path这个数组的大小如果达到k,说明我们找到了一个子集大小为k的组合了。

    此时用result二维数组把path保存起来,并终止本层递归。

    if (path.size() == k) {
    	result.push_back(path);
    	return;
    }
    
  • 单层搜索的过程
    for循环每次从startIndex开始遍历,然后用path保存取到的节点i。

    for (int i = startIndex; i < n; i++) {
    	path.push_back(i); // 处理节点
    	backtracking(n, k, i + 1); // 递归,控制树的纵向遍历,注意下一层搜索要从i + 1 开始
    	path.pop_back(); // 回溯,撤销处理的节点
    }
    

代码实现

class Solution {
private:
	vector<vector<int>> result; 
	vector<int> path;
	void backtracking(int n, int k, int startIndex) {
		if (path.size() == k) {
			result.push_back(path);
			return;
		}
		for (int i = startIndex; i < n; i++) {
			path.push_back(i);
			backtracking(n, k, i + 1);
			path.pop_back();
		}
	}
public:
	vector<vector<int>> combine (int n, int k) {
		result.clear();
		path.clear();
		backtracking(n, k, 1);
		return result;
	}
};
  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值