代码随想录 | 回溯算法 ● 理论基础 ● 77. 组合
  gWLBg59q0ceP 2023年11月02日 51 0

理论基础

  • 组合问题:N个数里面按一定规则找出k个数的集合(不强调顺序)
  • 切割问题:一个字符串按一定规则,有几种切割方式
  • 子集问题:一个N个数的集合里,有多少符合条件的子集
  • 排列问题:N个数按一定规则全排列,有几种排列方式(强调顺序)
  • 棋盘问题:N皇后,解数独等
回溯法模板
  • 回溯函数模板返回值以及参数

返回值一般为void

参数的确定比较困难,一般是需要什么参数,就填什么参数


  • 回溯函数终止条件

回溯函数一般用在树的结构上,当遍历到树的叶子节点,就找到了满足条件的一条答案,把这个答案存放起来,并结束本层循环。


  • 回溯搜索的遍历过程

回溯一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度,for循环就是遍历集合区间,可以理解一个节点有多少个孩子,这个for循环就执行多久。

代码随想录 | 回溯算法 ● 理论基础  ● 77. 组合_搜索

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

第77题. 组合

力扣题目链接(opens new window)

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

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

解析:

可以按照上面的回溯方式,照猫画虎。首先,要知道这是个组合问题,那么就是没有顺序的,即[1,2]和[2,1]算是一种组合,而不是两种。

按照模板套的话即是如下的代码:

class Solution {
    List<Integer> list = new ArrayList<>();
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> combine(int n, int k) {
        backTracking(n,k,1);
        return result;
    }
    void backTracking(int n, int k, int startIndex){
        if(list.size() == k){
            result.add(new ArrayList<>(list));
            return ;
        }
        for(int i = startIndex; i <= n; i++){
            list.add(i);
            backTracking(n,k,i+1);
            list.remove(list.size()-1);
        }
    }
}

优化:

剪枝操作,有点深,我是看了卡尔哥的视频,再结合底下“独舞鸾”的解析,才明白剪枝操作如何找边界。

首先,list.size(): 表示已经找到的个数

k-list.size(): 表示还需要找的个数

则[startIndex , n] 的数组长度起码应该是k - list.size() 才有可能继续搜索,则存在n - startIndex + 1 = k - list.size() , 则startIndex = n + 1 - (k-list.size()) , 也就是说startIndex 不能超过这个值。

class Solution {
    List<Integer> list = new ArrayList<>();
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> combine(int n, int k) {
        backTracking(n,k,1);
        return result;
    }
    void backTracking(int n, int k, int startIndex){
        if(list.size() == k){
            result.add(new ArrayList<>(list));
            return ;
        }
        for(int i = startIndex; i <= n+1-k+list.size(); i++){
            list.add(i);
            backTracking(n,k,i+1);
            list.remove(list.size()-1);
        }
    }
}


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  rvP2pqm8fEoB   2023年12月24日   34   0   0 ListJavaListJava
gWLBg59q0ceP