EDIT:根据澄清的问题调整答案
主要思想:同样,结果选择可以像自定义一样进行编码数字系统 http://en.wikipedia.org/wiki/Numeral_system。人们可以增加一个计数器并将该计数器解释为一个选择。
但是,由于选择的大小有一个额外的限制==target
。
实现限制的一种简单方法是仅检查结果选择的大小并跳过不满足限制的选择。但这很慢。
所以我所做的就是做一些更聪明的增量来跳转到
直接选择正确尺寸。
抱歉,代码是Python 语言。
但我是用类似于 Java 迭代器接口的方式做到的。
输入输出格式为:
haves[i] := multiplicity of the i-th item in the collection
target := output collection must have this size
代码:
class Perm(object):
def __init__(self,items,haves,target):
assert sum(haves) >= target
assert all(h > 0 for h in haves)
self.items = items
self.haves = haves
self.target = target
self.ans = None
self.stop = False
def __iter__(self):
return self
def reset(self):
self.ans = [0]*len(self.haves)
self.__fill(self.target)
self.stop = False
def __fill(self,n):
"""fill ans from LSB with n bits"""
if n <= 0: return
i = 0
while n > self.haves[i]:
assert self.ans[i] == 0
self.ans[i] = self.haves[i]
n -= self.haves[i]
i += 1
assert self.ans[i] == 0
self.ans[i] = n
def __inc(self):
"""increment from LSB, carry when 'target' or 'haves' constrain is broken"""
# in fact, the 'target' constrain is always broken on the left most non-zero entry
# find left most non-zero
i = 0
while self.ans[i] == 0:
i += 1
# set it to zero
l = self.ans[i]
self.ans[i] = 0
# do increment answer, and carry
while True:
# increment to the next entry, if possible
i += 1
if i >= len(self.ans):
self.stop = True
raise StopIteration
#
if self.ans[i] == self.haves[i]:
l += self.ans[i]
self.ans[i] = 0
else:
l -= 1
self.ans[i] += 1
break
return l
def next(self):
if self.stop:
raise StopIteration
elif self.ans is None:
self.reset()
else:
l = self.__inc()
self.__fill(l)
return self.ans
请注意,items
参数并没有真正被使用。
The assert
in the __init__
是为了明确我对输入的假设。
The assert
in the __fill
只是为了显示一个方便的属性self.ans
在这样的背景下__fill
叫做。
这是一个用于测试代码的很好的框架:
test_cases = [([3,2,1], 3),
([3,2,1], 5),
([3,2,1], 6),
([4,3,2,1,1], 4),
([1,3,1,2,4], 4),
]
P = Perm(None,*test_cases[-1])
for p in P:
print p
#raw_input()
输入结果示例([1,3,1,2,4], 4)
:
[1, 3, 0, 0, 0]
[1, 2, 1, 0, 0]
[0, 3, 1, 0, 0]
[1, 2, 0, 1, 0]
[0, 3, 0, 1, 0]
[1, 1, 1, 1, 0]
[0, 2, 1, 1, 0]
[1, 1, 0, 2, 0]
[0, 2, 0, 2, 0]
[1, 0, 1, 2, 0]
[0, 1, 1, 2, 0]
[1, 2, 0, 0, 1]
[0, 3, 0, 0, 1]
[1, 1, 1, 0, 1]
[0, 2, 1, 0, 1]
[1, 1, 0, 1, 1]
[0, 2, 0, 1, 1]
[1, 0, 1, 1, 1]
[0, 1, 1, 1, 1]
[1, 0, 0, 2, 1]
[0, 1, 0, 2, 1]
[0, 0, 1, 2, 1]
[1, 1, 0, 0, 2]
[0, 2, 0, 0, 2]
[1, 0, 1, 0, 2]
[0, 1, 1, 0, 2]
[1, 0, 0, 1, 2]
[0, 1, 0, 1, 2]
[0, 0, 1, 1, 2]
[0, 0, 0, 2, 2]
[1, 0, 0, 0, 3]
[0, 1, 0, 0, 3]
[0, 0, 1, 0, 3]
[0, 0, 0, 1, 3]
[0, 0, 0, 0, 4]
表现 Each next()
呼叫需要O(h)
where h
是项目类型的数量(大小haves
list).