之前使用c++ 写了一个全排列,
今天写了python版本,实现对实际应用题的解析
# 比如有N个数,选出M个排列,并且满足一定条件,则有多少种可能,或者极限值是多少?
# 比如1~8的数字,排列为一个5位数,能被99整除的最大数为多少?
# 正常来解,需要考虑满足9和11分别整除特性,
# 全局的结果集合,集合中每1条也是一个list
result = []
mapIndex = {} # 从字符到索引的反向索引表,用于检查那个已经使用了
callback = None # 过滤函数的指针,初始为空
############################################################
# 检查所有的标记是否都已经标记用过了,没有使用的返回索引,或者返回-1
def isUsedAll(used):
for i in range(len(used)):
if used[i] == 0:
return i
return -1
# 设置倒排索引
def setMap(lst):
global mapIndex
n = len(lst)
for i in range(n):
mapIndex[lst[i]] = i
# 根据值取索引
def getIndexBy(a):
global mapIndex
return mapIndex[a]
# 根据当前前缀生成一个列表,设置使用哪些
def markUsed(preFix):
global mapIndex
n = len(preFix)
used = [0] * len(mapIndex)
for i in range(n):
index = getIndexBy(preFix[i])
used[index] = 1
return used
#以当前前缀,测试其他没有标记使用过的
# 当数字栈为空时返回,
# 当前标记全使用完了,则输出序列,并退栈
# 当前标记没有使用完,则先选下一个可用的,标记,并对2个栈同时入栈
# 每一轮前缀的深度过程中,前缀部分不变,但是使用标记不停地增加,直到所有的标记都用完
def PermutationOneRoot(lst, stackNum, stackUsed, m):
global result
global callback
# 开始循环
while (len(stackNum) > 0):
currentPrefix = stackNum[-1] # 当前的前缀
currentUsed = stackUsed[-1] # 当前前缀情况下,遍历了几个了?
if (len(currentPrefix) >= m): # 达到了指定的长度,保存记录,并退栈
if (callback != None): # 如果设置了过滤函数
if callback(currentPrefix):
result.append(currentPrefix)
else: # 没有过滤函数直接添加
result.append(currentPrefix)
stackUsed.pop()
stackNum.pop()
continue # 执行下一轮循环
index = isUsedAll(currentUsed) # 当前前缀不足M个,则需要寻找下1个填充的的后缀
if (index == -1): # 当前前缀遍历结束,退栈
stackUsed.pop()
stackNum.pop()
continue
else:
currentUsed[index] = 1 # 标记使用了新找到的后缀
tmpPrefix = list(currentPrefix) # 拷贝当前前缀,补1个,生成一个新的前缀,
tmpPrefix.append(lst[index]) #
stackNum.append(tmpPrefix) # 压栈
tmpUsed = markUsed(tmpPrefix) # 根据新前缀标记新的使用标记
stackUsed.append(tmpUsed) # 压栈
return
#end of oneroot
# 输入一组数字,输出结果
def Permutation(lst, m):
stackNum = []
stackUsed = []
if (m > len(lst)):
m = len(lst)
setMap(lst)
# 每个数字分别作为前缀执行一遍:
n = len(lst)
for i in range(0, n):
# 当前数字为根节点的前缀,压栈,只有1个元素
currentData = [ lst[i] ]
stackNum.append(currentData)
used = [0] * n # 初始化当前使用标记,压栈
used[i] = True
stackUsed.append(used)
# 以每个数字为根节点,分别执行一次深度遍历排列
PermutationOneRoot(lst, stackNum, stackUsed, m)
#end of permutation
############################################################
# 准备开始使用:
#
# 打印结果
def printRet():
for i in result:
print(i)
# 转换为数字
def printRetAsNum():
for tmpList in result:
sum = 0
for i in tmpList:
sum = sum * 10 + i
print(sum)
# 这里定义用来扩展逻辑的回调函数
def checkCallBack(tmpList):
sum = 0
for i in tmpList: # 转换为数字
sum = sum * 10 + i
if (sum % 99) == 0:
return True
return False
# end callback
############################################################
lst = [1, 2, 3, 4, 5, 6, 7, 8]
m = 5
# 入口函数
callback = checkCallBack
Permutation(lst, m)
#printRet()
printRetAsNum()