[算法题解详细]回溯解力扣46全排列

题目

给定一个不含重复数字的数组 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. 1 <= nums.length <= 6
 2. -10 <= nums[i] <= 10
 3. nums 中的所有整数 互不相同

思路

这个题目对于我们都不陌生了,在高中数学就学过的排列组合,今天我们要用回溯法来找出所有可能的全排列
这里还有个关键点在我们需要定义一个和nums数组等大的bool数组用来标识某个数字是否已经被使用

n = nums.size();
vector<bool> record(n, false);//bool数组

然后在dfs函数中还有一个关键的参数用来表示递归层数,也是代表当前已经搜索到第几个数字
接下来我们看代码

代码

首先我们为了减少函数的参数,我们需要把一些东西定义到全局中,方便我们直接调用
如最后返回的答案vector容器,和储存每一个符合条件全排列的vector容器,以及我们需要常常使用的nums数组的大小n

class Solution {
    
    
public:
    int n;
    vector<int> temp;
    vector<vector<int>> ans;
};

在主函数中,我们将temp和ans容器先清空(这一步也可以不做),然后定义record数组,再直接进入dfs函数,并且传入递归层数参数为0,这里传0还有一个原因是因为数组下标是从0开始的,我们传入0会方便我们进行后续操作

class Solution {
    
    
public:
    int n;
    vector<int> temp;
    vector<vector<int>> ans;
    vector<vector<int>> permute(vector<int>& nums) {
    
    
        n = nums.size();
        ans.clear();
        temp.clear();
        vector<bool> record(n, false);
        dfs(nums, ans, 0, temp, record);
        return ans;
    }
};

在递归函数中,出口条件为u == n,这表示当前选中的数字已经是选完了nums数组中的所有数字,符合一个排列,所以此时我们要将这个排列加入我们的答案容器中,然后直接结束当前层递归,回溯到上一层递归中

 void dfs(vector<int>& nums, vector<vector<int>>& ans, int u, vector<int>& temp, vector<bool>& record) {
    
    
        if(u == n) {
    
    
            ans.push_back(temp);
            return;
        }
}

然后是在每一层搜索中,我们都需要对nums数组循环一遍,如果record数组是flase的话就代表还没有使用这个数字,因此我们可以使用,因为循环中我们把使用的record数组值改为了true,那么在dfs之后我们就需要恢复上一步的状态,也就是值重新赋为flase,这就是回溯,回溯到我们使用这个数字之前的状态,这里还要注意dfs函数中的传参,我们传给下一层dfs的u是传的u+1,因为这代表当前递归中我们已经选中了一个数字,u+1就是在下一层递归中我们要再选中一个数字,u代表我们选中的数字个数

void dfs(vector<int>& nums, vector<vector<int>>& ans, int u, vector<int>& temp, vector<bool>& record) {
    
    
        if(u == n) {
    
    
            ans.push_back(temp);
            return;
        }
        for(int i = 0; i < n; i++) {
    
    
            if(record[i] == false) {
    
    
                record[i] = true;
                temp.push_back(nums[i]);
                dfs(nums, ans, u + 1, temp, record);
                temp.pop_back();
                record[i] = false;
            }
        }
}

最后是完整代码:

class Solution {
    
    
public:
    int n;
    vector<int> temp;
    vector<vector<int>> ans;
    void dfs(vector<int>& nums, vector<vector<int>>& ans, int u, vector<int>& temp, vector<bool>& record) {
    
    
        if(u == n) {
    
    
            ans.push_back(temp);
            return;
        }
        for(int i = 0; i < n; i++) {
    
    
            if(record[i] == false) {
    
    
                record[i] = true;
                temp.push_back(nums[i]);
                dfs(nums, ans, u + 1, temp, record);
                temp.pop_back();
                record[i] = false;
            }
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
    
    
        n = nums.size();
        ans.clear();
        temp.clear();
        vector<bool> record(n, false);
        dfs(nums, ans, 0, temp, record);
        return ans;
    }
};

回溯在dfs中的使用十分的普遍,等之后有时间我会专门写一篇博客来详细介绍回溯法和dfs的使用。

猜你喜欢

转载自blog.csdn.net/m0_61607810/article/details/121132024