代码随想录day21|回溯算法入门:组合

文章:代码随想录

回溯算法其实就是暴力for循环,但是单纯for循环无法做到一些需要回溯的场景,今天做的就是这一道入门题 组合。

思路:

这一道题没办法直接通过for暴力求解,因为k是不固定的,k等于2可以用两层嵌套for去做,那嵌套k=50呢?手写50层for循环吗。所以这一题的暴力得用for和递归相结合,这就是经典的回溯算法.

那么我们的开始位置其实就是i,然后往i+1的位置往后递归,当收集到k个时,加入结果集,递归函数结束。回弹到上一层时,需要把最后加入的数字弹出,然后进入这一层的下一个循环i++.这其实和二叉树有一道打印出所有路径的题目很像,dfs前序遍历,然后从叶子节点往上逐层弹出上一个加入的节点。其实所有的回溯算法和这个原理是一样的。这里收集到k个其实就是遍历到了叶子节点,所以往上弹出最后一个到K-1的状态。然后再往右节点遍历找下一个最后元素。

代码:

 List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> combine(int n, int k) {
        backTracking(n, k, 1);
        return result;
    }

    private void backTracking(int n, int k, int start) {
        if (path.size() == k) {
            result.add(new ArrayList<Integer>(path));
            return;
        }

        for (int i = start; i <= n; i++) {
            path.add(i);
            backTracking(n, k, i + 1);
            //回溯
            path.remove(path.size() - 1);
        }
    }
     //剪枝优化
    //在剩下的元素数量数不能满足组成k的时候,这种分支其实可以修剪掉。
    //1.已经选择的元素个数:path.size();
    //2.还需要的元素个数为: k - path.size();
    //那么n-(k - path.size())就是最后一个能接受的开始位置,因为在这个位置之后开始,后面的元素已经不够组成k个了.
    //我们是从1开始,所以最后还要加1.-->n-(k - path.size())+1
    private void backTracking2(int n, int k, int start) {
        if (path.size() == k) {
            result.add(new ArrayList<Integer>(path));
            return;
        }

        for (int i = start; i <= n - (k - path.size()) + 1; i++) {
            path.add(i);
            backTracking(n, k, i + 1);
            //回溯
            path.remove(path.size() - 1);
        }
    }

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值