在本题中,是要求返回[1,n]这个数组的长度为k的组合。涉及到排列、组合、棋盘、分割等问题的时候,要考虑利用回溯来进行解决。 回溯和递归类似,也分为三步进行分析

确定递归函数的返回值和参数:一般来说返回值都是void,参数就需要根据题目来判断了。确定递归的终止条件确定单层处理的逻辑

那么一般的回溯题目都是可以套用模板的

void backtracking(参数) {

if (终止条件) {

存放结果;

return;

}

for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {

处理节点;

backtracking(路径,选择列表); // 递归

回溯,撤销处理结果

}

}

以本题为例,返回值为void,参数我们需要存放整体结果的一个二维数组,还需要一个存放单层结果的一维链表。还有n和k,还需要一个startIndex

然后我们确定截至条件,也就是我们单层处理的时候,链表的长度为k,那么就直接把这个一维链表放入到二维数组中。然后return

最后我们在单层处理的时候,也就是for循环,从startIndex开始进行循环遍历,将结果存入一维链表,然后进行递归调用,最后我们还需要回溯撤销,将存入的下一个元素删除,比如一开始我们得到1,2。我们需要把2删除,然后再加入3变成1,3.

class Solution {

List> result= new ArrayList<>();

LinkedList path = new LinkedList<>();

public List> combine(int n, int k) {

backtracking(n,k,1);

return result;

}

public void backtracking(int n,int k,int startIndex){

if (path.size() == k){

result.add(new ArrayList<>(path));

return;

}

for (int i =startIndex;i<=n;i++){

path.add(i);

backtracking(n,k,i+1);

path.removeLast();\\removelast可以删除链表最后一个元素并返回该元素

}

}

}

注意:removelast可以删除链表最后一个元素并返回该元素 result.add(new ArrayList<>(path)),之所以new ArrayList<>(path),是因为如果用result.add(path)会导致在向path中添加元素的时候,result发生变化。 res.add(new ArrayList(path)):开辟一个独立地址,地址中存放的内容为path链表,后续path的变化不会影响到res。 res.add(path):将res尾部指向了path地址,后续path内容的变化会导致res的变化

但是这里的代码是可以优化的,进行剪枝操作,来举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。比如 那么,我们只需要改变for循环的截至条件就可以了。比如n = 4,k = 3,那么目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。 从2开始搜索都是合理的,可以是组合[2, 3, 4]。从3开始的话就不能再有3个数字的组合了。 所以,截至条件是for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置

class Solution {

List> result = new ArrayList<>();

LinkedList path = new LinkedList<>();

public List> combine(int n, int k) {

combineHelper(n, k, 1);

return result;

}

/**

* 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex

* @param startIndex 用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。

*/

private void combineHelper(int n, int k, int startIndex){

//终止条件

if (path.size() == k){

result.add(new ArrayList<>(path));

return;

}

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){

path.add(i);

combineHelper(n, k, i + 1);

path.removeLast();

}

}

}

思路来源:代码随想录

文章链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。