回溯

2022-06-05  本文已影响0人  你大爷终归是你大爷

回朔算法是使用递归的方式,遍历所有的状态,一般借助数组等结构进行“剪枝”,较少遍历的次数。

解决的是 子集、组合、排列 问题。注意边界条件。
子集和排列和顺序无关,要借助位置信息防止重复;
排列和位置无关,只需判断辅助数据结构(path)中是否包含当前元素

下文介绍这几种的标准代码。

1、子集

力扣78题:给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

class Solution {

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

    public List<List<Integer>> subsets(int[] nums) {
        dfs(nums, 0);
        return res;
    }

    // 注意index的用法
    public void dfs(int[] nums, int index) {
        res.add(new ArrayList(path));
        for(int i=index;i<nums.length;i++) {
            path.add(nums[i]);
            dfs(nums, i+1);
            path.remove(path.size()-1);
        }
    }
}

2、组合

组合是在子集的基础上进行剪枝,过程中不匹配直接返回,不在继续递归。
力扣77:给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

class Solution {

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

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

    public void dfs(int n, int k, int index) {
        // 剪枝:组合是特定的子集,保留符合的
        if(k == path.size()) {
            res.add(new ArrayList(path));
            return ;
        }
        for(int i=index;i<=n;i++) {
            path.add(i);
            dfs(n, k, i+1);
            path.remove(path.size()-1);
        }
    }
}

3、排列

力扣46题: 全排列 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

class Solution {

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

    public List<List<Integer>> permute(int[] nums) {
        dfs(nums);
        return res;
    }

    public void dfs(int[] nums) {
        if(path.size() == nums.length) {
            res.add(new ArrayList(path));
            return;
        }
        for(int i=0;i<nums.length;i++) {
            if(path.contains(nums[i])) {
                continue;
            }
            path.add(nums[i]);
            dfs(nums);
            path.remove(path.size()-1);
        }

    }
}
上一篇 下一篇

猜你喜欢

热点阅读