回溯问题—排列组合

回溯法其实与深度优先搜索区别不大,模板也基本上一致,如下:

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

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

77. 组合

下面这个代码是排列,注意排列和组合的区别,排列记录是否访问,组合不用。

 	ArrayList<Integer> temp = new ArrayList<>();;
    List<List<Integer>> res = new ArrayList<>();;
    int[] visit;
    public void dfs(int n , int k){
    
    
        if(temp.size()==k){
    
    
            ArrayList clone = (ArrayList)temp.clone();
            res.add(clone);
            return;
        }
        for (int i = 0; i < n ; i++) {
    
    
            if(visit[i]==0){
    
    
                visit[i]=1;
                temp.add(i+1);
                dfs(n,k);
                visit[i]=0; //回溯
                temp.remove(temp.size()-1); //回溯
            }
        }
    }
    public List<List<Integer>> combine(int n, int k) {
    
    
        visit = new int[n];
        Arrays.fill(visit,0);
        dfs(n,k);
        return res;
    }

下面这段是组合,组合是需要记录步数的,即下一次不能包含本次遍历的数。

在这里插入图片描述

	ArrayList<Integer> temp = new ArrayList<>();;
    List<List<Integer>> res = new ArrayList<>();;

    public void dfs(int n , int k,int step){
    
    
        if(temp.size()==k){
    
    
            ArrayList clone = (ArrayList)temp.clone();
            res.add(clone);
            return;
        }

        for (int i = step; i <= n ; i++) {
    
    //横向遍历
            temp.add(i);
            dfs(n,k,i+1); //纵向遍历,只能取i之后的数
            temp.remove(temp.size()-1); //回溯
        }
    }
    public List<List<Integer>> combine(int n, int k) {
    
    
        dfs(n,k,1);
        return res;
    }

组合问题的优化剪枝:

​ 剪枝原理:假设n=4,k=4,只有step=1时才有结果,后面的step>1都取不到4个数,因此可以在for循环内判断是否满足数目的要求,从而避免无效搜索。

        for (int i = step; i <= n-(k-temp.size()) ; i++) {
    
    //横向遍历优化,留足数目
            temp.add(i);
            dfs(n,k,i+1); //纵向遍历,只能取i之后的数
            temp.remove(temp.size()-1);
        }

216. 组合总和 III

class Solution {
    
    
    List<List<Integer>> res = new ArrayList<>();
    ArrayList<Integer> temp = new ArrayList<>();
    int sum = 0;

    public void dfs(int k, int n, int step) {
    
    
        if (temp.size() == k && sum == n) {
    
    
            ArrayList<Integer> clone = (ArrayList<Integer>) temp.clone();
            res.add(clone);
            return;
        }
        for (int i = step; i <= 9 ; i++) {
    
     // 优化  9 - (k - temp.size())
            if(sum+i>n){
    
    
                continue;
            }
            temp.add(i);
            sum += i;
            dfs(k, n, i + 1);
            sum -= i;
            temp.remove(temp.size() - 1);
        }
    }
    public List<List<Integer>> combinationSum3(int k, int n) {
    
    
        dfs(k, n, 1);
        return res;
    }
}

参考:https://programmercarl.com/0077.%E7%BB%84%E5%90%88%E4%BC%98%E5%8C%96.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

猜你喜欢

转载自blog.csdn.net/cj151525/article/details/129939492