最近上班上到脑袋都晕,,,突然想到要复习一下。就搞了个子集树的代码。。
其实子集树有点像暴力破解,大名鼎鼎的0-1规划中的背包问题一样。假设有N个背包,对应N个元素。
那么有:
背包 | 1 | 2 | 3 | ... | n |
要/不要 | 要/不要 | 要/不要 | 要/不要 | 要/不要 | 要/不要 |
然后要、不要分别对两种情况,好比二叉树的左子树和右子树一样。
子集树写法也参考了背包问题,遍历N个背包,分别决定要不要该背包,然后遍历整棵树。
当发现遍历层数满了以后,就打印路径即可~
if num == len(arr):
outputList.append([arr[index] for index in range(0, num) if cur_arr[index] ])
return
当层数未满,那么继续尝试
1、要该背包
2、不要该背包
对应代码:
# 选第num个元素
cur_arr[num] = 1
subSetTree(arr, cur_arr, num + 1, outputList)
# 不选第num 个元素
cur_arr[num] = 0
subSetTree(arr, cur_arr, num + 1, outputList)
那么问题来了,如果将该元素append进一个数组中,然后执行完了再弹出可以吗?
【不可以】原理很简单,这个子集树肯定遍历该树的所有路径,如果往里面append元素,那么必然会涉及到重复添加元素。。。必然涉及到处理以后情况
1、某一路径到头了,可能回头走若干步,然后再继续往下走。。。这时候涉及的问题就巨复杂了。。。
2、由于递归之后,数组中的元素大小已经发生了变化,这时候如果使用
cur_arr[num] = cur_arr[:-1]
会导致修改错数据。。。。
3、反正这种处理是巨恶心的。。。
def subSetTree(arr, cur_arr, num, outputList):
if num == len(arr):
outputList.append([arr[index] for index in range(0, num) if cur_arr[index] ])
return
# 选第num个元素
cur_arr[num] = 1
subSetTree(arr, cur_arr, num + 1, outputList)
# 不选第num 个元素
cur_arr[num] = 0
subSetTree(arr, cur_arr, num + 1, outputList)
def subSetTree(arr, cur_arr, num, outputList):
if len(arr) == num :
outputList.append([val for val in cur_arr if val != None])
return
# 选第num个元素
cur_arr[num] = arr[num]
subSetTree(arr, cur_arr, num + 1, outputList)
# 不选第num 个元素,删除第num个元素
cur_arr[num] = None
subSetTree(arr, cur_arr, num + 1, outputList)
arr = [1, 2, 3]
cur_arr = range(0,3)
outputList = []
num = 0
subSetTree(arr, cur_arr, num, outputList)
for arr in outputList:
print arr