组合算法笔记1
三、直观递归
利用直观方式进行递归组合,从左到右,依次选择每个元素
- 为了避免组合重复,组合结果要按照第一组的前m个元素和后m个元素,即首位元素的遍历范围序号是[1,n-m]
- 找到首位元素后,其余候选元素的组合即为相同问题的子问题,进而递归
- 组合遍历
def testsample(srclist, num):
if num > 1:
rlist = []
for i in range(len(srclist) - num + 1):
ret = testsample(srclist[i + 1:], num - 1) # 组合剩余元素
for r in ret: # 每个剩余元素组合都接上当前选择的元素
r.insert(0, srclist[i])
rlist.extend(ret)
return rlist # 返回当前的所有组合
else: # 1个元素时每个剩余元素都是一个组合
return [[i] for i in srclist]
t = testsample([1, 2, 3, 4, 5, 6], 3)
print(t)
for i in t:
print(i)
- 缺点:产生的中间list过多,且不够精简
- 根据组合元素的扫描顺序,可以将所有的组合遍历共用一个list,减少大量的临时list
def combination(srclist, num) :
def comb(srclist, num, result):
for i in range(len(srclist), num - 1, -1):
result[num - 1] = srclist[i - 1]
if (num > 1):
comb(srclist[:i-1], num - 1, result)
else:
print(result)
comb(srclist, num, [0] * num)
combination(srclist, 3)
- 进阶版,根据python语言特性,优化精简代码
def combination(srclist, num):
ret = [0] * num
def comb(srclist, num, ret):
for i in range(len(srclist) - num + 1):
ret[-num] = srclist[i]
if num > 1:
yield from com(srclist[i + 1:], num - 1, ret)
else:
yield list(ret)
yield from com(srclist, num, ret)
t = test(srclist, 3) # 返回一个生成器对象
for i in t:
print(i)
# 优化
def combine(src, num):
ret = [0] * num
num -= 1 # -1 mark the max combination index
def comb(index, start):
'''
param::index 组合元素预留索引位置
param::start 源序列元素索引起始点
'''
for si in range(start, len(src) + index - num):
ret[index] = src[si]
if index < num:
yield from comb(index + 1, si + 1)
else:
yield ret
yield from comb(0, 0)
yield
和yield from
关键字是python
语言的功能,不方便转换成其他语言
def test(srclist, num):
ret = [0] * num
def com(srclist, num, ret):
r = []
for i in range(len(srclist) - num + 1):
ret[-num] = srclist[i]
if num > 1:
r.extend(com(srclist[i + 1:], num - 1, ret))
else:
r.append(list(ret))
return r
return com(srclist, num, ret)
t = test(srclist, 3) # 返回的是list[list]
print(t)
for i in t:
print(i)