LeetCode刷题--- 全排列 II

 前言:这个专栏主要讲述递归递归、搜索与回溯算法,所以下面题目主要也是这些算法做的  

我讲述题目会把讲解部分分为3个部分:
1、题目解析

2、算法原理思路讲解

3、代码实现


全排列 II

题目链接: 全排列 II

题目

给定一个可包含重复数字的序列 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]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

解法

题目解析

给我们可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列

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

算法原理思路讲解    

因为题⽬不要求返回的排列顺序,因此我们可以对初始状态排序,将所有相同的元素放在各⾃相邻的位置,⽅便之后操作。因为重复元素的存在,我们在选择元素进⾏全排列时,可能会存在重复排列。
我们如何使他们不重复呢?
我们只关心不合法(合法)的分支即可
1.同一个节点的所有分支相同的数字只能用一次
2.同一个数只能用一次
一、画出决策树

 

 决策树就是我们后面设计函数的思路


二、设计代码

(1)全局变量

vector<int> path;          // 存储路径
vector<vector<int>> ret; 
bool check[10] = {false};  
  • 定义⼀个⼆维数组 ret ⽤来存放所有可能的排列
  • ⼀个⼀维数组 path ⽤来存放每个状态的排列
  • ⼀个⼀维数组 check 标记元素 

(2)设计递归函数

void dfs(vector<int>& nums, int pos);
  • 参数:pos(当前需要填⼊的位置);
  • 返回值:⽆;
  • 函数作⽤:查找所有合理的排列并存储在答案列表中


 前提:这个数组是有序的

递归流程如下:
  1. 定义⼀个⼆维数组 ret ⽤来存放所有可能的排列,⼀个⼀维数组 path ⽤来存放每个状态的排列⼀个⼀维数组 check 标记元素,然后从第⼀个位置开始进⾏递归;
  2. 在每个递归的状态中,我们维护⼀个步数 pos,表⽰当前已经处理了⼏个数字;
  3. 递归结束条件:当 pos 等于 nums 数组的⻓度时,说明我们已经处理完了所有数字,将当前数组存⼊结果中;
  4. 在每个递归状态中,枚举所有下标 i,若这个下标未被标记,并且在它之前的相同元素被标记过, 则使⽤ nums 数组中当前下标的元素:
    1. 将 check[i] 标记为 true;
    2. 将 nums[i] 添加⾄ path 数组末尾;
    3. 对第 pos+1 个位置进⾏递归;
    4. 将 check[i] 重新赋值为 false,并删除 path 末尾元素表⽰回溯;
  5. 最后,返回 ret


代码实现

  • 时间复杂度:O(n×n!),其中 n 为序列的长度。
  • 空间复杂度:O(n)。我们需要 O(n) 的标记数组,同时在递归的时候栈深度会达到 O(n)O(n)O(n),因此总空间复杂度为 O(n+n)=O(2n)=O(n)
class Solution 
{
    vector<int> path;          // 存储路径
    vector<vector<int>> ret; 
    bool check[10] = {false};  

    void dfs(vector<int>& nums, int pos)
    {
        if (pos == nums.size())
        {
            ret.push_back(path);
            return;
        }

        for (int i = 0; i < nums.size(); i++)
        {
            if (check[i] == false && (i == 0 || nums[i] != nums[i - 1] || check[i - 1] != false))
            {
                path.push_back(nums[i]);
                check[i] = true;
                dfs(nums,pos+1);
                path.pop_back();
                check[i] = false;
            }
        }
    }
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) 
    {
        sort(nums.begin(),nums.end());
        dfs(nums,0);

        return ret;
    }
};

  • 62
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 31
    评论
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

-元清-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值