回溯算法11-全排列(Java)

11.全排列

  • 题目描述

给定一个不含重复数字的数组 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,2,3][1,3,2]被视为两个不同的集合,这与组合数不同的是组合数应该考虑如何避免重复,我们用到了startIndex去标记每次遍历的数来实现,那么对于排列数,我们应该考虑的是,怎么可以不漏掉每一个排列数呢?

image-20240310112418015

通过观察,每个排列数均在叶子节点,在每次递归过程中,我们只需要将还未遍历的元素加入到我们的集合之中,就可以完成这一操作。对于如何知道哪个元素已经遍历,哪个元素为遍历,我们可以使用一个used数组去标记,如果使用过标记为1.这样我们每次把used元素中为0的元素加入到集合之中,便可以实现此方法。
1.首先,定义了两个全局变量 path 和 result,分别用于存储当前的路径和最终的结果。path 是一个链表,用于暂时存储当前的排列,result 是一个列表,用于存储所有的排列组合。

2.然后,定义了一个 permute 方法,接受一个整数数组 nums 作为参数,并返回所有排列的列表。在该方法中,首先初始化了一个长度与 nums 相同的数组 used,用于标记每个数字是否被使用过。然后调用 backtrack 方法开始搜索排列。

3.在 backtrack 方法中,首先判断当前的排列长度是否等于 nums 的长度,如果是,则将当前排列加入到 result 中,并返回。接着,使用一个循环遍历 nums 数组中的每个元素,对于每个元素,如果它已经被使用过,则跳过当前循环。如果没有被使用过,则将其标记为已使用,添加到 path 中,然后递归调用 backtrack 方法继续搜索下一层排列,当递归结束后,将当前元素从 path 中移除,并将其标记为未使用,以便尝试其他可能的排列组合。

4.通过这样的回溯过程,最终可以得到所有的排列组合。
  • Java代码实现
// 定义一个全局变量,用于存储当前的路径
LinkedList<Integer> path = new LinkedList<>();
// 定义一个全局变量,用于存储最终的结果
List<List<Integer>> result = new ArrayList<>();

/**
 * 生成给定数组的所有排列
 * @param nums 给定的整数数组
 * @return 所有排列的列表
 */
public List<List<Integer>> permute(int[] nums) {
    // 初始化一个数组,用于标记每个数字是否被使用过
    int[] used = new int[nums.length];
    // 开始回溯搜索排列
    backtrack(nums, used);
    // 返回最终的结果
    return result;
}

/**
 * 回溯方法,用于生成排列
 * @param nums 给定的整数数组
 * @param used 数字使用情况的数组
 */
private void backtrack(int[] nums, int[] used) {
    // 当当前路径长度等于数组长度时,将当前排列加入到结果中
    if (path.size() == nums.length) {
        result.add(new ArrayList<>(path));
        return;
    }

    // 遍历数组中的每个元素
    for (int i = 0; i < nums.length; i++) {
        // 如果当前元素已经被使用过,则跳过
        if (used[i] == 1) continue;
        
        // 标记当前元素为已使用
        used[i] = 1;
        // 将当前元素添加到路径中
        path.add(nums[i]);
        // 递归调用回溯方法,继续生成排列
        backtrack(nums, used);
        // 将当前元素从路径中移除
        path.removeLast();
        // 标记当前元素为未使用,以便尝试其他组合
        used[i] = 0;
    }
}

2.全排列II

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值