#全排列 递归写法
def permute(nums,l,r):if l==r: #如果l=r 说明指剩下最后一个元素了 返回当前列表print(''.join(nums)) #字符串连接else:for i in range(l,r+1): #进入循环#交换i l 两个元素位置nums[l],nums[i]=nums[i],nums[l]#递归 调用permute(nums,l+1,r) #l+1 表示下一个元素#再交换回来nums[l],nums[i]=nums[i],nums[l]if __name__ == '__main__':nums=['1','2','3']permute(nums,0,len(nums)-1)使用 nums = ['1', '2', '3'] 这个例子,我们可以详细解释 permute 函数是如何运行的。
首先,我们初始化 nums 为一个包含三个元素的列表:['1', '2', '3']。我们的目标是生成这三个元素的所有可能排列。
调用 permute(nums, 0, 2),其中 0 是左边界,2 是右边界。
1. 当 l = 0, r = 2○ i = 0:交换 nums[0] 和 nums[0](实际上没有变化),然后递归调用 permute(nums, 1, 2)。■ l = 1, r = 2 时,会生成 ['1', '2', '3']、['1', '3', '2'] 的排列。当 l = 1, r = 2 时,我们考虑 nums 列表中索引为 1 和 2 的元素,即 '2' 和 '3'。此时,'1' 已经被固定在列表的第一个位置,所以我们只需要考虑 '2' 和 '3' 的排列。
递归调用 permute(nums, 1, 2) 的过程如下:
1. 初始状态:nums = ['1', '2', '3'],此时 l = 1 指向 '2',r = 2 指向 '3'。
2. i = 1(即 l 的值):○ 不进行交换,因为 nums[l](即 '2')和 nums[i](也是 '2')相同。○ 递归调用 permute(nums, l + 1, r),此时 l + 1 = 2,r 仍为 2。由于 l 和 r 相等,说明只剩下一个元素需要排列,直接打印出这个排列。■ 内部递归调用:nums 仍为 ['1', '2', '3'],因为 l 和 r 相等,所以直接打印 ['1', '2', '3']。○ 递归返回后,没有交换操作,因为 i 和 l 相同。
3. i = 2:○ 交换 nums[l](即 '2')和 nums[i](即 '3'),nums 变为 ['1', '3', '2']。○ 递归调用 permute(nums, l + 1, r),此时 l + 1 = 2,r 仍为 2。同样地,因为 l 和 r 相等,直接打印出这个排列。■ 内部递归调用:nums 为 ['1', '3', '2'],直接打印 ['1', '3', '2']。○ 递归返回后,将 nums[l] 和 nums[i] 交换回来,恢复 nums 为 ['1', '2', '3']。
所以,当 l = 1, r = 2 时,通过递归调用和元素交换,我们生成了 ['1', '2', '3'] 和 ['1', '3', '2'] 这两个排列。这是因为 '1' 已经被固定在第一个位置,我们只需要考虑剩余两个元素的排列情况。后续也是如此○ i = 1:交换 nums[0] 和 nums[1],得到 ['2', '1', '3'],然后递归调用 permute(nums, 1, 2)。■ l = 1, r = 2 时,会生成 ['2', '1', '3']、['2', '3', '1'] 的排列。○ i = 2:交换 nums[0] 和 nums[2],得到 ['3', '2', '1'],然后递归调用 permute(nums, 1, 2)。■ l = 1, r = 2 时,会生成 ['3', '2', '1']、['3', '1', '2'] 的排列。
在每次递归调用之后,我们都会将元素交换回它们原始的位置,以确保在下一次循环中,我们可以正确地处理下一个元素。
这样,permute 函数通过不断地交换元素和递归调用自身,最终生成了 ['1', '2', '3']、['1', '3', '2']、['2', '1', '3']、['2', '3', '1']、['3', '2', '1'] 和 ['3', '1', '2'] 这六个全排列。
#2.用 itertools模块
import itertools
lst=list(itertools.permutations([1,2,3]))
for item in lst:print(item)
全排列问题 递归实现 有重复情况
‘’‘如果有重复元素,为了避免生成重复的排列,可以在递归之前进行判断,确保相同的元素不会交换位置。在进行交换之前,
检查是否存在相同的元素,如果存在则跳过当前循环。’‘’
可以用一个集合来保存已经交换过的元素 然后进行判断 如果集合里面有当前元素 说明该元素是重复元素 直接跳过
def permute(nums, l, r):if l == r: # 如果l=r 说明指剩下最后一个元素了 返回当前列表print(''.join(nums)) # 连接else:visited=set() #用集合记录已经交换过的元素for i in range(l, r + 1): # 进入循环if nums[i] in visited: #如果在集合里面 表示已经交换过 跳过continue# 交换i l 两个元素位置nums[l], nums[i] = nums[i], nums[l]# 递归 调用permute(nums, l + 1, r) # l+1 表示下一个元素# 再交换回来nums[l], nums[i] = nums[i], nums[l]visited.add(nums[i])if __name__ == '__main__':nums = ['1', '2', '2']permute(nums, 0, len(nums) - 1)