字符串全排列:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
交换法
把字符串分成两部分:第一个字符,和剩余的字符串。因此求字符串的排列,就可以:
- 可以出现在第一个字符位置的字符:把第一个字符和字符串中剩余的所有字符交换;
- 固定第一个字符,递归求剩余字符串的排列。
def getAllRankRecursion(lstOri:list)->set:
result = set()
if not lstOri:
return result
def addResult(rank):
get = ''.join(rank)
result.add(get)
print(get)
def needSwap(rank, start, end)->bool:
for i in range(start,end):
if rank[i] == rank[end]:
return False
return True
def helper(rank:list, start:int):
if start==len(rank)-1:
addResult(rank)
return
helper(rank, start+1)
for i in range(start+1, len(rank)):
if(needSwap(rank, start, i)):
rank[i], rank[start] = rank[start], rank[i]
helper(rank, start+1)
rank[i], rank[start] = rank[start], rank[i]
helper(lstOri, 0)
return result
注意:在字符串中有重复字符时,需要确定是否需要交换。若字符在前面字符串中已出现过,则不需要交换;即第i个数与第j个数交换时,要求[i,j)中没有与第j个数相等的数。
字典序法
先对字符串排序(从小到大),然后查找其下一个排列(如"1234"的下一个排列就是"1243"),依次反复查找,即得到了全排列。如何查找下一个排列(以926520为例):
- 从后向前查找第一对相邻的递增数:即26;
- 查找到的一对字符中,前面的字符即为替换数(对应位置即为交换点a):即2;
- 从后面查找比替换数大的最小的数:即5;
- 交换2与5(即956220),然后将交换点后面的字符串反序(即950226)。
def getAllRankWhile(rank:list)->set:
def nextPermutation(rank:list)->bool:
for i in range(len(rank)-1, 0, -1):
if rank[i-1]<rank[i]: # get the first Non-increase seq
changed = i-1
least = i
for j in range(i+1, len(rank)):
if rank[changed]<rank[j] and rank[least]>=rank[j]:
least = j
# change the elements, and reverse
rank[changed], rank[least] = rank[least], rank[changed]
rank[i:] = rank[:i-1:-1]
return True
return False
result = set()
rank.sort()
while True:
get = ''.join(rank)
print(get)
result.add(get)
if not nextPermutation(rank):
break;
return result