全排列一般分為不重復和有重復
1.無重復
無重復的話一般都是n!種排列
1.1遞歸回溯法
時間復雜度:O(n * n!)
主體思想就是換位:每一個位置有和其他位置換位和不換位兩種情況,假設限制有三個字母[a,b,c]
每次將首位字母與后面的字母依次換位置,每次結(jié)束后將后一位的看作首字母。(但是為了不影響后面的結(jié)果,每次都要回溯,換了位置之后還要把位置換回來)
f([a])=[a]
f([a,b]) = [a,f(b)],[b,f(a)]
f([a,b,c]) = [a,f([b,c])],[b,f([a,c])],[c,f([a,b])]
[a,f([b,c])] = [a,b,f(c)],[a,b,f(b)]
[b,f([a,c])] = [b,a,f(c)],[b,c,f(a)]
[c,f([a,b])] = [c,a,f(b)],[c,b,f(a)]
最后的結(jié)果就是[a,b,c],[a,c,b],[b,a,c],[b,c,a],[c,a,b],[c,b,a]
共6種情況
listpath = []
start = 0
ss = ['1','2','3']
def permuation(start,ss,listpath):
if start==len(ss):
listpath.append(''.join(ss))
else:
for i in range(start,len(ss)):
ss[start],ss[i]=ss[i],ss[start]
#start+1而不是i+1,因為這里每一次都是在start內(nèi)循環(huán)完畢之后再交換縮小
# i大部分時候比start大,會直接導致有些位置并沒有交換
permuation(start+1,ss,listpath)
ss[start],ss[i]=ss[i],ss[start]
permuation(start,ss,listpath)
print(listpath)
#out:['123', '132', '213', '231', '321', '312']
1.2
2.有重復
有重復的話就每次考慮交換位置的兩個元素是否相等,相等的話就沒必要換了,重復了
listpath = []
ss = ['1','1','3']
start = 0
def permuation(start,ss,listpath):
if start==len(ss):
print(ss)
listpath.append(''.join(ss))
print(listpath)
else:
for i in range(start,len(ss)):
if i==start or ss[start]!=ss[i]:
ss[start],ss[i]=ss[i],ss[start]
permuation(start+1,ss,listpath)
ss[start],ss[i]=ss[i],ss[start]
permuation(start,ss,listpath)
print(listpath)
#out:['113', '131', '311']