回溯算法题目总结 全排列、组合、子集问题 Java版本

题型一:排列、组合、子集相关问题

提示:这部分练习可以帮助我们熟悉「回溯算法」的一些概念和通用的解题思路。解题的步骤是:先画图,再编码。去思考可以剪枝的条件, 为什么有的时候用 used 数组,有的时候设置搜索起点 begin 变量,理解状态变量设计的想法。

  1. 全排列(中等)
  2. 全排列 II(中等):思考为什么造成了重复,如何在搜索之前就判断这一支会产生重复;
  3. 组合总和(中等)
  4. 组合总和 II(中等)
  5. 组合(中等)
  6. 子集(中等)
  7. 子集 II(中等):剪枝技巧同 47 题、39 题、40 题;
  8. 第 k 个排列(中等):利用了剪枝的思想,减去了大量枝叶,直接来到需要的叶子结点;
  9. 复原 IP 地址(中等)

目录

题型一:排列、组合、子集相关问题

题解步骤小总结

46. 全排列

47. 全排列 II

39. 组合总和

40. 组合总和 II

78. 子集

90. 子集 II


题解步骤小总结

1. 先画图、确定递归的树        

2. 考虑 每一层开始的位置 begin

    组合和子集问题不能从0开始选用 i == start

3. 结束条件

    排列是跟踪数组长度== nums.length, 组合target = 0, 子集是 当前层不能继续遍历

4. 剪枝

    全排列不用减、组合需要 nums[i] > target不用再搜索、子集不用减枝

5. 去重

    核心思想是在递归树的同一层不要使用相同元素去向下搜索,

    具体而言可以使用两种方式:

                 方式一: Set   set.contains(nums[i])

                 方式二:i > 同一层开始的位置 used[i-1] == false;

46. 全排列

难度中等1737

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

示例 1:

输入:nums = [1,2,3]输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]输出:[[1]]

提示:

  • 1 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同

题解

1. 先画图,清楚整个递归回溯的过程。为编码确定细节做准备

2. 是否使用used数组

因为是排列,每个结果集都需要包括所有元素,所以需要用used数组,这样从根节点到子节点遍历的过程中,整个路径就不会有重复的元素。

3. 搜索起点遍历

每一层搜索起点的变量可以从0开始,因为已经使用了used数组来去掉不能使用的元素,然后按照顺序选择第一个不能使用的元素即可

4. 如何去重

没有重复元素不需要去重,保证每个路径是争取的即可

5. 剪枝

判断used数组是不是用就可以帮忙剪枝了

6. 结束条件

存储遍历结果的 curList 长度为nums数组长度就可以结束了

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList();
        helper(new ArrayList(), result, nums , new boolean[nums.length]);
        return result;
    }
    private void helper(List<Integer> curList,List<List<Integer>> result, int[]nums, boolean[]used){
        if(curList.size() == nums.length){ // 结束条件
            result.add(new ArrayList(curList));
        } else {
            for(int i = 0; i< nums.length; i++){
                if(used[i]) continue; // 搜索的过程中,子节点不能和之前节点访问的相同
                curList.add(nums[i]);
                used[i] = true;
                helper(curList, result, nums, used);
                curList.remove(curList.size()-1);
                used[i] = false;
            }
        }
    }
}

47. 全排列 II

难度中等916

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]输出:

[[1,1,2],

[1,2,1],

[2,1,1]]

示例 2:

输入:nums = [1,2,3]输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

题解

方法一:

 Set<Integer> curDepthUsedSet = new HashSet<>(); //记录每一层使用过的节点

通过Set记录当前层使用过的节点数值,从而保证了当前层只能使用相同数值一次

class Solution {
    public List<List<Integer>> 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值