leetcode 77 组合

leetcode 77 组合_第1张图片

原题链接

  1. 首先要定义结果集合res和判断集合长度的队列path,写终止条件,然后进入递归函数,最后返回结果集res

  2. 递归函数部分:首先写终止条件,在什么条件下将结果集进行保存?res.add(new ArrayList<>(path));

  3. 然后是回溯的模板如下:
    for循环横向选择{
    进行操作(path.addLast(i))
    然后递归
    最后要撤销之前的操作path.removeLast()
    }

    优化方法:对上述的方法进行剪枝 —> 分析搜索起点的上界进行剪枝
    搜索起点的上界 + 接下来要选择的元素个数 - 1 = n
    其中,接下来要选择的元素个数 = k - path.size(),整理得到:
    搜索起点的上界 = n - (k - path.size()) + 1
    就是把 i <= n 改成 i <= n - (k - path.size()) + 1 :

  4. 二刷:对关键位置进行剪纸,主要的作用就是避免多选元素(即避免path.size() 长度超出k 之后,还会进行判断)通过这样设定,可以限定在最长的位置结束。

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    Deque<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        if(n < k) return res;
        recur(n, k, 1);
        return res;
    }
    public void recur(int n, int k, int begin){
        if(path.size() == k){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i = begin; i <= n - (k - path.size()) + 1; i++){
            path.addLast(i);
            recur(n, k, i + 1);
            path.removeLast();
        }
    }
}







class Solution {

    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res = new ArrayList<>();
        //首先写终止条件,当。。。。
        if (k <= 0 || n < k) {
            return res;
        }
        // 从 1 开始是题目的设定
        //定义一个队列path
        Deque<Integer> path = new ArrayDeque<>();
        dfs(n, k, 1, path, res);
        return res;
    }
    //如下是递归函数 题目要求是返回范围从1开始,然后定义队列path 和 结果集合 res
    private void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> res) {
        // 递归终止条件是:path 的长度等于 k
        if (path.size() == k) {
            //当以上条件满足的时候,将此时的path加入到res中
            res.add(new ArrayList<>(path));
            return;
        }

        // 遍历可能的搜索起点
        for (int i = begin; i <= n; i++) {
            // 向路径变量里添加一个数
            path.addLast(i);
            // 下一轮搜索,设置的搜索起点要加 1,因为组合数理不允许出现重复的元素
            dfs(n, k, i + 1, path, res);
            // 重点理解这里:深度优先遍历有回头的过程,因此递归之前做了什么,递归之后需要做相同操作的逆向操作
            path.removeLast();
        }
    }
}


//对上述的方法进行剪枝  --->  分析搜索起点的上界进行剪枝-----------------------------
//对上述的方法进行剪枝  --->  分析搜索起点的上界进行剪枝-----------------------------
//对上述的方法进行剪枝  --->  分析搜索起点的上界进行剪枝-----------------------------
//对上述的方法进行剪枝  --->  分析搜索起点的上界进行剪枝-----------------------------

class Solution {
    /**

     */
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res = new ArrayList<>();
        if(k <= 0 || n < k){
            return res;
        }
        Deque<Integer> path = new ArrayDeque<>();
        dfs(n, k, 1, path, res);
        return res;
    }
    //如下是递归函数 题目要求是返回范围从1开始,然后定义队列path 和 结果集合 res
    private void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> res){
        if(path.size() == k){
            res.add(new ArrayList<>(path));
            return;
        }
    // 搜索起点的上界 + 接下来要选择的元素个数 - 1 = n
    // 其中,接下来要选择的元素个数 = k - path.size(),整理得到:
    // 搜索起点的上界 = n - (k - path.size()) + 1
    // 把 i <= n 改成 i <= n - (k - path.size()) + 1 :
        for(int i = begin; i <= n -(k - path.size()) + 1; i++){
            path.addLast(i);
            dfs(n, k, i + 1, path, res);
            path.removeLast();
        }
    }
}

你可能感兴趣的:(回溯,leetcode,深度优先,算法)