排列(数字序列 & str序列)
38 字符串的排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。输入: [1,2,3]
leecode 46
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def dfs(first): # first 记录每次开始的第一个位置 #[位置 #递归function的 参数是?想清楚很important]
if first == n: # 当起始位置超越数组长度了,停止,加入结果集
res.append(nums[:]) # 这里要加入其复制,不然传的是引用,会被后面修改
for i in range(first, n): # 第一个数字与后面所有数字依次交换
nums[first], nums[i] = nums[i], nums[first]
dfs(first + 1) # 递归替换下一个位置
nums[first], nums[i] = nums[i], nums[first] # 回溯,还原,才能进行下一次交换!
n = len(nums)
res = []
dfs(0)
return res
#知识点
#python
#深&浅copy之一
nums=[3,6,2]
#test1
a=[]
a.append(nums[:]) #传的是nums contents复制,即nums改变,a不会随之改变
nums[0], nums[1] = nums[1], nums[0] #a=[3,6,2]
#test2
b=[]
b.append(nums) #传的是nums引用,即nums改变,b也随之改变 b=[3,6,2]
nums[0], nums[1] = nums[1], nums[0] #b=[6, 3, 2]
输入一个字符串序列,长度不超过9(可能有字符重复),字符只包括大小写字母。
#simple解法
class Solution:
def Permutation(self, ss):
if len(ss) <= 1:
return ss
res = set()
# 遍历字符串,固定第一个元素,第一个元素可以取a,b,c...,然后递归求解
for i in range(len(ss)):
for j in self.Permutation(ss[:i] + ss[i+1:]): # 依次固定了元素,其他的全排列(递归求解)
res.add(ss[i] + j) # 集合添加元素的方法add(),集合添加去重(若存在重复字符,排列后会存在相同,如baa,baa)
return sorted(res) # sorted()能对可迭代对象进行排序,结果返回一个新的list
#复杂解法
#ss(str)-->【分】先变成list-->【合】变回str
def Permutation(self, ss):
def dfs(first): # first 记录每次开始的第一个位置
if first == n: # 当起始位置超越数组长度了,停止,加入结果集
res.add(''.join(ss))
for i in range(first, n): # 第一个数字与后面所有数字依次交换
ss[first], ss[i] = ss[i], ss[first]
dfs(first + 1) # 递归替换下一个位置
ss[first], ss[i] = ss[i], ss[first] # 回溯,还原,才能进行下一次交换!
if not ss: return []
n = len(ss)
res = set()
ss = list(ss)
dfs(0)
return sorted(res) # sorted()能对可迭代对象进行排序,结果返回一个新的list
#知识点
ss='abc'
ss = list(ss)
''.join(ss)
Out[37]: 'abc'
ss
Out[38]: ['a', 'b', 'c']
''.join(ss)
Out[39]: 'abc'
组合
38.2 字符串的所有组合
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
返回的结果包括空列表。
leecode78
dp[i] = dp[i-1] + [each+[nums[i]] for each in dp[i-1]]
解法一:动态规划
def subsets_1(self, nums: List[int]) -> List[List[int]]:
res = [[]]
for x in nums:
res += [ each+[x] for each in res]
return res
解法二:回溯,递归
依次加入,走到底了就回溯。
input: [1, 2, 3]
[out]: 1, 12, 123, 13, 2, 23, 3
def subsets_2(self, nums: List[int]) -> List[List[int]]:
def dfs(first): # first 指向当前第一个元素
res.append(sub[:]) # 复制并加入结果集
if first == len(nums): # 若first走完了数组,返回
return
# 这里与全排列相比,不用交换数字,即数组的顺序是固定的。只需要依次加入元素就可以。
for i in range(first, len(nums)): # 从当前位置到末尾依次遍历
sub.append(nums[i]) # 加入当前元素
dfs(i + 1) #【!!与排列区别】(防止重复)# # 从下一个位置开始递归
sub.pop() # 回溯,去除sub中的元素,为了下一次遍历
res = []
sub = [] # 中间量,因组合,长度一直在change
n = len(nums)
dfs(0)
return res
Tips: list类型 可以object.pop()
位运算
共有n个字符,对应n位bit,总共有2**n种排列,哪一位为1则将对应位置的字符加入到子集中
#法一
def subsets_3(self, nums: List[int]) -> List[List[int]]:
n=len(nums)
res=[]
for i in range(2**n,2**(n+1)): #保持二进制是n长度 2**n是(n+1)长度 bin(2**2)=>100
bit = bin(i)[3:]
res.append( [nums[j] for j in range(len(bit)) if bit[j] =='1'])
return res
#法二
def subsets(self, nums: List[int]) -> List[List[int]]:
if not nums: return []
res = []
for i in range(2 ** len(nums)): #e.g:n=3 0~7
sub = []
for j in range(len(nums)): #0~2
if i >> j & 1:
sub.append(nums[j])
res.append(sub)
return res
知识点
bin(x) x -- int 或者 long int 数字
>>>bin(521)
#这里的显示结果形式与我们平时习惯有些差别,主要是前面多了0b,这是表示二进制的意思。
'0b1000001001'
res.append([nums[j] for j in range(len(bit)) if bit[j] == '1'])
等价于
sub=[]
for j in range(n):
if bit[j]=='1':
sub.append(nums[j])
res.append(sub)
排列(实际problem):
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
leecode 51
我们如果把 queens, xy_dif, xy_sum 三个状态的变化全部放入递归函数的变量中,则不需要我们手动回溯了,递归时会自动还原上一次的变量。
解法一:
回溯步骤:
: 从第一行第一列开始遍历。循环列并且试图在每个 column 中放置皇后
: 停止条件:若棋子数目等于n,满足要求加入结果。
: 若满足要求则放置棋子。
: 回溯,拿掉棋子,恢复状态。
#简洁版
"""dfs,把需要回溯的状态放入递归函数的变量可自动回溯。
"""
def solveNQueens_2(self, n):
def dfs(queens, xy_dif, xy_sum):
row=len(queens)
if len(queens)==n:
result.append(queens)
return
for col in range(n): #相当于广度优先搜索,故可找出all sol
if not( col in queens or row-col in xy_dif or row+col in xy_sum ): #摩尔根定律:非(并)=(非交)#row-col不能加abs
dfs(queens+[col], xy_dif+[row-col], xy_sum+[row+col])
result=[]
dfs([],[],[])
return [["."*i + "Q"+"."*(n-i-1) for i in sol] for sol in result]
#Tip:
sol=[1, 3, 0, 2]
a=[x for x in sol]
等价于
a=[]
for x in sol:
a.append(x)