递归算法 -- 解决全排列问题

递归算法 – 解决全排列问题

首先我们来看题目

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

示例 1:

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

让后我们来看给的代码样列

class Solution {
    public List<List<Integer>> permute(int[] nums) {

    }
}

分析

从代码的样例我们可以看到最终我们是要返回一个嵌套集合 , 也就说一个大的集合包裹多个小的集合

如何迭代?

在这里插入图片描述

1. 初始化
  • 成员变量:
    • List<List<Integer>> res:用于存储所有可能的排列。
    • ArrayList<Integer> solu:用于存储当前正在构建的排列。
    • boolean[] bool:一个布尔数组,用于跟踪哪些数字已经被使用(在原始代码中,这个变量被错误地声明了两次,一次在类级别,一次在permute方法内部,应只保留在方法内部的声明)。
  • 方法:
    • List<List<Integer>> permute(int[] nums):主方法,接受一个整数数组nums,返回其所有排列的列表。
    • void dfs(int index, int[] nums):深度优先搜索(DFS)的递归函数,用于生成排列。index表示当前处理到nums数组的哪个位置。
2. DFS逻辑
  • 基准情况:

    • index等于nums的长度时,表示已经成功构建了一个排列,将其添加到结果集res中,并返回。
  • 递归步骤:

    • 遍历

      nums
      

      数组中的每个元素(索引为

      i
      

      • 如果当前元素未被使用(

        !bool[i]
        

        ),则进行以下操作:

        • 将当前元素添加到solu中,表示选中了这个元素作为当前排列的一部分。
        • bool[i]设置为true,表示该元素已被使用。
        • 递归调用dfs(index + 1, nums),注意这里index递增,表示处理下一个位置。
        • 回溯:在递归返回后,将solu中的最后一个元素移除,并将bool[i]重置为false,以便尝试其他可能的排列。
public class PaiLieShu {
    // 定义结果集合
    List<List<Integer>> res = new ArrayList<>();
    //定义每一种结果
    ArrayList<Integer> solu = new ArrayList<>();
    boolean[] bool;

    public List<List<Integer>> permute(int[] nums) {


        // 定义判断数组--> 判断该数字是否以及被使用
        boolean[] bool = new boolean[nums.length];
        // 定义初始位置
        int index = 0;
        // 计算nums长度
        int len = nums.length;
        dfs(index , nums);

        return res;
    }

    // 定义迭代函数
    public void dfs(int index , int[] nums){
        /*
            这里的index代表着nums数组的索引 , 我们每加入一个数字index就会加一
            当index=索引长度时表示找到了一种结果
         */
        if ( index == nums.length){
            // 将结果加入到集合中
            res.add(new ArrayList(solu));
            return;
        }

        // 这里进行三次循环相当于创建树的过程
        for (int i = 0; i < nums.length; i++) {
            // 判断该位置的数字是否被使用过, 如果没有则循环
            if (!bool[i]){
                // 假如当前i=0 , 在第一次循环中没被使用
                // 那么接下来需要对nums[i]进行储存
                solu.add(nums[i]);
                // 将索引为i的位置设置为使用过了
                bool[i] = true;

                // 递归调用
                dfs(index + 1 , nums);

                // 回溯 , 删除最后一个数
                solu.remove(solu.size() - 1);
                bool[i] = false;

            }
        }


    }
}

为什么要回溯?

看下图 , 我们来像一个问题, 如果不回溯会产生什么样的问题?

很显然不回溯的情况下回答之我们定义的bool判断数组中全为true , 那么就算进入下一次迭代 , 由于全为true并不会执行实际的代码 , 从而导致最终结果只有[[1,2,3]]

而进行回溯可以巧妙的解决这个问题使得每一次迭代都从树的根节点开始

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攒了一袋星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值