递归使用模板总结

1.递归简介

在许多问题上面,递归算法可以帮组我们快速高效地解决问题,例如涉及树、棋盘、迷宫、排列、组合、子串等问题,每一类问题都可以体现出相同的一种规律。

递归的关键在于设置合适的终止条件,这得需要大量经验的积累,我也是在不断学习~

2.模板

2.1 深搜的索引取(pos+1)

依次遍历的顺序如下(从上至下,从左至右):关键就在于DFS(res, pos+1),pos位置的变化会导致不同的回溯

0    1    2    3                         1    1    2    3                          2    1    2    3                         3    1    2    3

0    1    3    3                         1    1    3    3                          2    1    3    3                         3    1    3    3

0    2    2    3                         1    2    2    3                          2    2    2    3                         3    2    2    3

0    2    3    3                         1    2    3    3                          2    2    3    3                         3    2    3    3

0    3    2    3                         1    3    2    3                          2    3    2    3                         3    3    2    3

0    3    3    3                         1    3    3    3                          2    3    3    3                         3    3    3    3

#include <iostream>
#include <vector>
using namespace std;

void DFS(vector<int>& res, int pos) {
	if (pos >= 4) {
		return;
	}
	for (int i = pos; i < 4; ++i) {
		res.push_back(i);
		DFS(res, pos+1);
		res.pop_back();
	}
}

int main()
{
	vector<int> res;
	DFS(res, 0);
	return 0;
}

2.2 全排列

2.1的基础之上,我们只需稍加改动就成为全排列算法,分析2.1的执行过程我们可以发现,搜索的下一个状态的起始遍历位置取决于上一个pos+1的值,所以按照上面那种回溯,我们是无法从在每个位置从0开始遍历的,全排列最直接的方法无非就是在每一个位置上面要保证从0-n进行选择,为了将当前的起始遍历位置从0开始,i设置为0,但会带来前面出现过的元素会再次出现,例如前面已经出现过1,后面就要避免出现1,那么我们就可以设置变量记录当前元素的状态,如果没有出现过,取当前元素,若出现过,就跳过,当回溯到上一个状态的时候,重新恢复它的状态.

当然还有其他比较简单的写法,但这种写法是比较容易的,而且可以加深对递归的理解.

#include <iostream>
#include <vector>
using namespace std;

void DFS(vector<int>& res, vector<int> flag, int pos) {
	if (pos >= 4) {
		return;
	}
	for (int i = 0; i < 4; ++i) {
		if (flag[i] == true) continue;
		flag[i] = true; //标记当前位置
		res.push_back(i);
		DFS(res, flag, pos+1);
		res.pop_back();
		flag[i] = false;
	}
}

int main()
{
	vector<int> flag(4, false);
	vector<int> res;
	DFS(res, flag, 0);
	return 0;
}

2.3 深搜的索引取(i+1)

依次遍历的顺序如下(从上至下):2.1只是帮助我们理解递归的过程,以下的这种情况就很有用了

0    1    2    3 

0    1    3

0    2    3

0    3

1    2    3

1    3

2    3

3

#include <iostream>
#include <vector>
using namespace std;

void DFS(vector<int>& res, int pos) {
	if (pos >= 4) {
		return;
	}
	for (int i = pos; i < 4; ++i) {
		res.push_back(i);
		DFS(res, i+1);
		res.pop_back();
	}
}

int main()
{
	vector<int> res;
	DFS(res, 0);
	return 0;
}

2.4 组合

2.3的算法稍做点改动,就是组合算法啦,观察可以知道,上述过程是逐渐递增的,这过程和我们的组合过程是很类似的,例如从4个数里面选择两个数.设m=4、n=2,那么正常的思路就是[0 1]——>[0 2]——>[0 3]——>[1 2]——>[1 3]——>[2 3],这和2.3的执行过程是很相似的,如果仔细观察,就会发现其实这个过程和上面不同的地方在于终止条件不一样而已

#include <iostream>
#include <vector>
using namespace std;

void DFS(vector<int>& res, int pos) {
	if (res.size() == 2) {
		return;
	}
	for (int i = pos; i < 4; ++i) {
		res.push_back(i);
		DFS(res, i+1);
		res.pop_back();
	}
}

int main()
{
	vector<int> res;
	DFS(res, 0);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值