leetcode.46数字的全排列

本文深入解析LeetCode上的全排列算法题目,包括无重复数字的全排列、含重复数字的全排列及字母大小写全排列等。文章提供了详细的递归和非递归解法,帮助读者理解和掌握全排列算法的实现。

leetcode.46 全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

全排列是将一组数按一定顺序进行排列,如果这组数有n个,那么全排列数为n!个。现以{1, 2, 3, 4, 5}为例说明如何编写全排列的递归算法。

1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。由于一个数的全排列就是其本身,从而得到以上结果。

2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合。
从而可以推断,设一组数p = {r1, r2, r3, … ,rn}, 全排列为perm§,pn = p - {rn}。因此perm§ = r1perm(p1), r2perm(p2), r3perm(p3), … , rnperm(pn)。当n = 1时perm(p} = r1。为了更容易理解,将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。

思路一:递归解法
Code1

res = []
def permute(nums, begin, end):
	if begin == end:
		tmp = nums[:]     # 要对nums进行深拷贝
		res.append(nums)
		#print(nums)
	else:
		for i in range(begin, end):
			nums[begin], nums[i] = nums[i], nums[begin]     # 将第一个数字依此与后面的数字进行交换
			permute(nums, begin+1, end)
			nums[begin], nums[i] = nums[i], nums[begin]    # 换回来
	return res

Code2

class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        def backtrack(nums, tmp):
            if not nums:
                res.append(tmp)
                return 
            
            for i in range(len(nums)):
                backtrack(nums[:i] + nums[i+1:], tmp + [nums[i]])
        backtrack(nums, [])
        return res      

思路二:非递归

def permute(nums):
	L = []
	queue = []
	for i in range(len(nums)):
		temp = nums[:]
		temp.pop(i)
		queue.append([ [nums[i] ], temp])
	
	# queue形成如[[[1], [2, 3]], [[2], [1, 3]], [[3], [1, 2]]]
	# 依次对[[1], [2,3]], [[2], [1,3]], [[3], [1,2]]
	while queue:
		for i in range(len(queue)):
			cur, rest = queue.pop(0)
		
			if not rest:
				L.append(cur)
			
			# 依此对rest中的数字添加到cur中(即对rest进行排列),如[2,3], [1,3], [1,2]
			for i in range(len(rest)):
				cur_new = cur[:]
				rest_new = rest[:]
				cur_new.append(rest[i])
				rest_new.pop(i)
	
				queue.append([ cur_new, rest_new ])
		
	return L
		

leetcode47. 全排列 II

给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

思路一:递归解法
此题的解法在上题(无重复数字的全排列)得到的结果上去重即可

class Solution(object):
    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        
        def backtrack(nums, tmp):
            if not nums:
                #if tmp not in res:
                    res.append(tmp)
                    return 
            for i in range(len(nums)):
                if i > 0 and nums[i] == nums[i-1]:   # 去掉这个if判断就是全排列,只需要在没有重复数字的全排列上加上这个if判断即可
                    continue
                backtrack(nums[:i] + nums[i+1:], [nums[i]] + tmp )
        nums.sort()   # 先排序, 这样相同的数字会排到一起
        backtrack(nums, [])
        return res

leetcode784. 字母大小写全排列

给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合。

示例:
输入: S = “a1b2”
输出: [“a1b2”, “a1B2”, “A1b2”, “A1B2”]

输入: S = “3z4”
输出: [“3z4”, “3Z4”]

输入: S = “12345”
输出: [“12345”]

注意:
S 的长度不超过12。
S 仅由数字和字母组成。

class Solution(object):
	def letterCasePermutation(self, S):
		if not S:
			return [S]
		
		# 递归S中除S[0]的字符串S[1:]
		rest = self.letterCasePermutation(S[1:])
		
		if S[0].isalpha():
			return [S[0].lower + s for s in rest] + [S[0].upper + s for s in rest]
		return [S[0] + s for s in rest]

leetcode17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

在这里插入图片描述

示例:

输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].

说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

class Solution(object):
    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        dig_map = {'2':'abc','3':'def','4':'ghi','5':'jkl',
                   '6':'mno','7':'pqrs','8':'tuv','9':'wxyz'}
        # 解法一
        # if not digits:
        #     return []
        
        # list_1 = ['']
        # for i in digits:
        #     list_1 = [x + y for x in list_1 for y in dig_map[i]]
        # return list_1
        
        # 解法一
        if not digits:
            return []
                        
        res = ['']
        for i in digits:
            next_res = []
            for j in dig_map[i]:
                for k in res:
                    next_res.append(k+j)
                    
            res = next_res
        return res
                    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值