001. 组合
创始人
2024-02-20 05:33:31
0

1.题目链接:

77. 组合

2.大概思路:

2.1题目要求:

给两个值 n 和 k ,要求从[1,n]的区间中,输出所有元素数量为k的组合。(不能有[1,1],值只能取一次)

2.2思路:

通过回溯法(递归)来做。(就是按n叉树的方式处理)

一条大目录,大目录里有小目录,一层层递归,到大目录的下一个节点,i+1,遍历完输出结果(输入一个初始值,这里为 1 )

2.3回溯三部曲:(有递归就有回溯)

2.3.1.递归函数的返回值以及参数

无返回值,只是遍历添加元素,参数就是传n和k,需要定义两个数组来存储临时数组和结果集。

vector> result; // 存放符合条件结果的集合
vector path; // 用来存放符合条件单一结果
void backtracking(int n, int k, int startIndex) 

2.3.2.回溯函数终止条件

到达叶子节点终止(也就是元素个数达到了k),同时把此时临时数组存储的结果输入到结果集。

if (path.size() == k) {result.push_back(path);return;
}

2.3.3.单层搜索的过程

因为要遍历大目录,所以用for循环,又因为要遍历大目录里面的小目录,所以要在遍历大目录的for循环里加 递归逻辑,同时在本层加回溯逻辑(返回上来代表下面一层遍历结束),达到终止条件返回,会进行回溯操作,方便小目录节点,记录不同的元素数值,在一个元素确定的情况下,也就是上一层。

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

2.3.4.总代码:

class Solution {
private:vector> result; // 存放符合条件结果的集合vector 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> combine(int n, int k) {result.clear(); // 可以不写path.clear();   // 可以不写backtracking(n, k, 1);return result;}
};

3.优化.剪枝操作

3.1.思路

为了方便更好的看出剪枝的效果,设置n=4,k=4,

剪枝的操作是为了去除不必要的遍历过程,如下图,被剪掉的部分,都是不能满足剩余可挑选的元素数量大于等于k的条件的,比如第二层开始,从取2开始已经可以剪掉了,第三层,从取3开始也可以剪掉了,

这也是判断条件。

 

3.2.操作

理解原理后在哪里操作来完成剪枝?下面是组合里单层搜索过程的代码

for (int i = startIndex; i <= n; i++) {path.push_back(i);backtracking(n, k, i + 1);path.pop_back();
}

修改的就是“ i <=n "这里,修改这里的原因就是想让for循环的范围缩小,遇见被剪枝的范围,就退出for循环。

改成这样

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置

 " i <= n - (k - path.size()) + 1 " 这是怎么来的?

得出过程如下:

  1. 已经选择的元素个数:path.size();

  2. 还需要的元素个数为: k - path.size();

  3. 这是满足题目条件的不等式:列表中剩余元素(n-i) >= 所需需要的元素个数(k - path.size() )

  4. 化简得i <= n - (k - path.size() ),i 超过这个范围的都是需要被剪掉的,满足这个条件代表,只遍历必要的区域,这样就完成了剪枝操作。

  5. 最后等式为: i <= n - (k - path.size()) + 1

为啥有个+1?

 " i <= n - (k - path.size()) + 1 " 是遍历范围,i 是有起始值的,下面是题目要求

 可见起始条件为1(起始点+满足条件的范围)

(感觉还是糊涂x)

4.遇见的问题:

怎么先记录一个,后面再接着记录下一个?

哦哦,进入for(大目录)默认已经记录一个了,后面的递归都是在小目录的for里记录的。

5.记录:

一开始遇见有点懵,理解了一点后,有点不知道该怎么说清楚

其实也不是很难对吧,但没能表述明白,怎么表述明白?我一直没尝试过,都是自己把理解到的思路直接拍上去,先写一遍代码吧,然后再考虑修正的问题。

运行成功!在来看看。好吧,讲不出来。算了,积累是渐进式的,一下加几个有效的模块,感觉作用也不大,都是要一个经历的过程的,虽然会有很多浪费,但没办法,我没法懂...讲解的清楚和思维导图这两个领域暂时触摸不到

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...