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