LeetCode刷题(python版)——Topic47全排列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]]

二、基本思路

        遇到组合、切割、子集、排列、棋盘(八皇后、数独)问题用回溯法回溯法的基本套路格式如下

def backtracking(参数):
    if 终止条件: # 达到叶子节点
        收集数据
        return
    # 单层逻辑
    for i  in range(lens):#遍历数据集
        处理节点
        backtracking(参数)
        撤销处理节点的操作

        对于该题我们只需要确定:

        1.函数的参数:生成的是不同的排列,则我们需要一个列表res存放最后的所有排列,用列表tmp存放当前的数据,用flag数组作为标记数组表示当前数是否取到的状态。故我们的回溯函数则有三个参数:(1)tmp,初始状态为[]  (2)flag,初始状态为[ 0 for i in range(所给列表长度)] (3)nums,用于把每次的数组值nums[i]加到tmp中。(注:列表与int不能直接相加)

        2.终止条件:当tmp中的元素个数与原数组个数相等时即为一次全排列。

        3.处理节点:本题对于单层节点的处理可以分为以下三个步骤:3.1 去重:对已取到元素的排除;3.2 剪枝:剔除相同结果排列;3.3 对取到当前节点做标记。

          3.1 去重:遍历全部元素集,当flag[i] == 1时,即已取过该元素,则跳过。这就是对已取到元素的排除。

          3.2 剪枝:剔除相同结果排列。在开始对所给列表按值进行升/降序,使得相同的数相邻。当在某下标之前的且与当前下标元素值相同但当前没取过时,则跳过,即为剪枝。样例如下图所示:

           3.3 对取到当前节点做标记:flag[i] = 1

        4.backtracking(参数):(1) nums:不变 (2) tmp:加上准备放入的元素nums[i] (3) flag:不变,已修改

        5.撤销处理节点的操作:将flag[i] 置为0即可,下次还可以被选择。

def permuteUnique(self, nums):
        def backtracking(nums,tmp,flag):
            if len(tmp) == len(nums):# 到叶子节点
                res.append(tmp)# 保存结果
                return
            for i in range(len(nums)):# 遍历元素集
                if flag[i] == 1:# 当该元素被取到了就跳过
                    continue
                if i > 0 and nums[i] == nums[i-1] and flag[i-1] == 0:# 当
                    continue
                flag[i] = 1 # 取当前元素,flag[i]置为1
                backtracking(nums,tmp + [nums[i]],flag) # 递归
                flag[i] = 0 # 回溯,flag[i]置为0不取当前数了
        res = []
        nums.sort()
        flag = [0 for _ in range(len(nums))]
        backtracking(nums,[],flag)
        return res

四、效率总结

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值