Leetcode 77. 组合(Java实现 超详细注释!)

Leetcode 77. 组合

回溯算法的入坑题,其实本质就递归暴力搜索 + 回退,我觉得这道题最难的点在于怎么剪枝(我其实在文中说的也不是很清楚,后面理解透了会回来补充完善!原谅现在的我也不知道该怎么表达,我尽力了,哈哈哈,勿喷!),加了详细的注释,方便日后复习,也希望能帮到其他小伙伴,如有错误,欢迎指正!

Java实现:

class Solution {
    // 为了递归的参数尽可能少,这里把path和res都作为类变量,不影响算法的整体流程
    List<List<Integer>> res = new ArrayList<>();
    Stack<Integer> path = new Stack<>();
    public List<List<Integer>> combine(int n, int k) {
        // 主方法中我们只要开启递归就可以,初始的start是从1开始(题目给定1 — n)
        backtracking(n,k,1);
        return res;
    }
    private void backtracking(int n,int k,int start){
        // 回溯的第一步就是设置退出递归的条件,当然就是当搜索的结果满足题目要求的时候,我们就可以将当前的path存入res中,并退出递归
        if (path.size() == k){
            res.add(new ArrayList<Integer>(path));
            return;
        }
        // 当没有满足退出的条件时,我们需要去不断地搜索;
        // 如初始第一层递归从1开始,将1push进path,接着进入第二层递归并再次进入for循环,此时start=2,所以将2push,那么什么时候停止进入for呢?
        // 其实最简单的方法就是全遍历,直接1 —— n全部遍历,但是效率低,我们需要进行剪枝;
        // 当i =  n - (k - path.size()),其实就没有必要再遍历了,因为k - path.size()表示当前还需要push几个元素才能输出解;
        // 也就是说必须备选要大于或等于k - path.size(),否则不可能有解
        // 即 “至多从哪里开始搜索” + 还需备选的元素个数 - 1 = n,否则无解,这里其实可以用归纳法,或者自己举个例子即可得到,比较难用语言描述
        // 至于为什么-1,是因为至多从哪里开始搜索和还需备选的元素个数其实重复一个元素,不减的结果会导致大于n
        // 那我们其实剪枝就是把i > “至多从哪里开始搜索”的部分减掉即可
        for (int i = start; i <= n - k + path.size() + 1; i++){
            // 这里其实就是第j层递归,不断地给path添加元素
            path.add(i);
            // 加完之后必须再递归,直到满足条件退出
            backtracking(n, k, i + 1);
            // 回溯的关键步骤:当我们找到了满足条件的解后,就直接将最后一个元素pop掉,相当于往回退一步,再继续搜索
            path.pop();
        }
    }
}

你可能感兴趣的:(Leetcode,leetcode)