【回溯法】回溯法解决全排列问题

本文详细解析了Python中如何实现给定数组的全排列,包括无重复元素的permutations()和允许重复元素的全排列思路,通过实例演示了backtracking算法和使用itertools库的不同方法。重点讨论了重复元素的去重策略和Python内置库在全排列问题上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        n = len(nums)
        def backtracking(nums, n):
            if len(path) == n:
                res.append(path[:])
                return
            for i in range(n):
 				 # 因为没重复元素,所以只需判断当前元素是		
 				 # 否在path数组中即可,不用used数组
                if nums[i] not in path:
                    path.append(nums[i])
                    backtracking(nums, n)
                    path.pop()
                else:
                    continue
                
        backtracking(nums, n)
        return res
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        def backtracking(nums, used):
            if len(path) == len(nums):
                res.append(path[:])
                return 

            for i in range(len(nums)):
                if used[i]: 
                    continue
                if i >= 1 and  nums[i] == nums[i-1] and not used [i-1]:
                    continue
                used[i] = 1
                path.append(nums[i])
                backtracking(nums, used)
                path.pop()
                used[i] = 0
            
        res = []
        path = []
        nums.sort()
        # used 初始化都是零,含义:在nums数组中没有元素被使用
        # used = [1, 0, 1,] 含义:nums[0],nums[2]已经被使用 
        used = [0 for i in range(len(nums))]
        backtracking(nums, used)
        return res
  • 这次的全排列问题和之前的子集,组合问题一样,一道不用去重,一道去重。
    这次的全排列也是,因为是全排列所以每层的遍历都是遍历整个nums数组,如果nums中元素不重复,那我们只需要判断新的nums[i]是否已经在path中,但是对于有重复元素的nums,我们就需要一个新的used数组来判断该数字是否使用过。
    注意:经过这几道题一定要注意,在每层上去重时,一定要先对原来的nums数组进行排序,让相同的元素挨在一起。

关于python内置的全排列,组合库

  • product 笛卡尔积  (有放回抽样排列)
    就是nums中元素可以重复使用

  • permutations 排列  (不放回抽样排列)
    nums中元素不可重复使用

  • combinations 组合,没有重复  (不放回抽样组合)
    nums中元素不可重复使用

  • combinations_with_replacement 组合,有重复  (有放回抽样组合)
    nums中元素可以重复使用

专业的解释还是要看官方啦:https://docs.python.org/3.10/library/itertools.html

"""
每个函数都有两参数,
第一个是可迭代对象,
第二个是要从可迭代对象中抽取出来进行 排列 或 组合 的元素个数
"""

import itertools
# lis 无重复元素
lis = ['a', 'b', 'c']
# 有放回排序(元素可以重复使用)
for i in itertools.product(lis, repeat=2):
    print(i, end=' ')
"""
有放回排序(元素可以重复使用):
('a', 'a') ('a', 'b') ('a', 'c') ('b', 'a') ('b', 'b') ('b', 'c') ('c', 'a') 
('c', 'b') ('c', 'c') 
"""

# 无放回排序(元素不可以重复使用)
for i in itertools.permutations(lis, 2):
    print(i, end=' ')
"""
无放回排序(元素不可以重复使用):
('a', 'b') ('a', 'c') ('b', 'a') ('b', 'c') ('c', 'a') ('c', 'b') 
"""


# 无放回组合(元素不可以重复使用)
for i in itertools.combinations(lis, 2):
    print(i, end=' ')
"""
无放回组合(元素不可以重复使用):
('a', 'b') ('a', 'c') ('b', 'c') 
"""

# 有放回组合(元素可以重复使用)
for i in itertools.combinations_with_replacement(lis, 2):
    print(i, end=' ')
"""
有放回组合(元素可以重复使用):
('a', 'a') ('a', 'b') ('a', 'c') ('b', 'b') ('b', 'c') ('c', 'c') 
"""


# lis2 中有重复元素
lis2 = ['a', 'a', 'c']
# 有放回排序(元素可以重复使用)
for i in itertools.product(lis2, repeat=2):
    print(i, end=' ')
"""
有放回排序(元素可以重复使用): (这个a比较多为了解释,输出顺序进行了调整)
('a', 'a')(第一个a是下标为0的a,第二个a是下标为0的a) 
('a', 'a')(第一个a是下标为0的a,第二个a是下标为1的a) 
('a', 'a')(第一个a是下标为1的a,第二个a是下标为0的a) 
('a', 'a')(第一个a是下标为1的a,第二个a是下标为1的a) 
('a', 'c') ('a', 'c') (情况与上面类似)
('c', 'a') ('c', 'a') 
('c', 'c') 
"""
# 无放回排序(元素不可以重复使用)
for i in itertools.permutations(lis2, 2):
    print(i, end=' ')
"""
无放回排序(元素不可以重复使用):
('a', 'a') ('a', 'c') ('a', 'a') ('a', 'c') ('c', 'a') ('c', 'a') 
"""
# 无放回组合(元素不可以重复使用)
for i in itertools.combinations(lis2, 2):
    print(i, end=' ')
"""
无放回组合(元素不可以重复使用):
('a', 'a') ('a', 'c') ('a', 'c') 
"""
# 有放回组合(元素可以重复使用)
for i in itertools.combinations_with_replacement(lis2, 2):
    print(i, end=' ')
"""
有放回组合(元素可以重复使用):
('a', 'a') ('a', 'a') ('a', 'c') ('a', 'a') ('a', 'c') ('c', 'c') 
"""
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值