力扣 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 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同

解1:设置标志数组+额外存储当前路径

最简单的方法就是基础的DFS,通过设置标志数组flag来记录已经元素是否选取过。

下图是以[0,1]示意递归过程:

查看代码
 class Solution {
public:
    vector<vector<int>> res;
    bool flag[6]={false};
    vector<int> cur;
    void dfs(vector<int> nums){
        if(nums.size()==cur.size())//cur排满了
        {
            res.emplace_back(cur);
            return;
        }
       
        for(int i=0;i<nums.size();i++){
            if(!flag[i]){//之前没有选择过
                cur.emplace_back(nums[i]);//选择当前
                flag[i]=!flag[i];//修改标志位
                dfs(nums);//进入递归
                flag[i]=!flag[i];//恢复标志位
                cur.pop_back();//退回之前的状态,清除之前的选择
            }
        }
    }  
    vector<vector<int>> permute(vector<int>& nums) {        
        dfs(nums);
        return res;
    }
};

解2:不设置标志数组+不额外存储当前路径

来自官方题解

可以节约掉标志数组,将原nums数组以下标idx划分为两个部分,左侧为已经选取的,右侧为没有选取的。在递归的时候动态维护Nums

Nums[0到idx-1]是已经选取过的数,而右边的[idx到len-1]是没有选取的,那么for循环可以以idx开始,i=idx:len-1,因为我们需要从[idx到len-1]这个范围选取一个元素,而元素一旦选取需要放在左边,所以我们选取当前元素i时,我们交换下标idx和下标i的元素值,这样每次选取下标i元素时,通过交换就可以维护Nums为选取的序列,当然,同上面的解法1,在出dfs后需要还原这个选取。

下图是以[0,1]示意递归过程:

 查看代码
class Solution {
public:
    vector<vector<int>> res;
    // bool flag[6]={false};
    vector<int> cur;
    void dfs(vector<int> outputs,int len,int idx){
        if(len==idx)//cur排满了
        {
            res.emplace_back(outputs);
            return;
        }
        for(int i=idx;i<len;i++){
           swap(outputs[i],outputs[idx]);//交换
           dfs(outputs,len,idx+1);
           swap(outputs[i],outputs[idx]);//恢复
        }
    }  
    vector<vector<int>> permute(vector<int>& nums) {        
        dfs(nums,nums.size(),0);
        return res;
    }
};
posted @ 2023-03-20 00:35  付玬熙  阅读(13)  评论(0编辑  收藏  举报