您可以进行以下观察:可能存在无效的序列:0前面应该总是有1或2。如果违反此规则,则应返回0(或引发异常)

输入中所有可以增加组合数的最小子序列都以1或2开头。因此,例如,一个以7开头的字符串将产生与删除该7后相同输入相同数量的组合。在

感兴趣的子序列(允许多个组合)可以彼此隔离,因为它们也有一个结尾:例如“2121212127”:这个序列不能再向右扩展一个字符,这将允许多个组合,因为结尾7永远不能与输入中的下一个字符组合。在

让“相关子序列”的定义为:任何一个子序列,如果被视为一个单独的输入,将返回2个或更多(组合计数),如果缩短一个字符,则返回一个较小的值(从其任一端删除一个字符),如果在子序列的任一侧增加1个字符,则不将返回更大的值(即,不是任何字符,而是作为输入的子序列)。匹配这些相关子序列的正则表达式是[12]*?(?:[3-6]|1[3-9]|(?=.0|$))

由一个相关子序列表示的组合数由以下递归形式给出(其中n是子序列的长度):

^{pr2}$

这是Fibonacci级数(移动一个索引位置,正如真正的Fibonacci有Fib(2) = 1,但这只是一个细节)。

所以,如果我们先找到最长的相关子序列,我们就会知道要生成多少个Fibonacci数(而不是更多!),而且只需要做一次。然后我们就可以得到对应于子序列长度的Fibonacci数的乘积。在

下面是实现这些想法的注释代码:

import re
from operator import mul
from functools import reduce # For Python 3.x
def get_combination(string):
def fib_to(n):
fibs = [1, 1] # Real Fibonacci would need [0, 1], but we want fib[2] to be 2.
for i in range(2, n+1):
fibs.append(fibs[-1] + fibs[-2])
return fibs
# Detect an invalid sequence, where a 0 occurs without a 1 or 2 preceding it
if re.search(r"(?
return 0
# Find all sub sequences where a variation is possible
sequences = re.findall(r"[12]*?(?:[3-6]|1[3-9]|(?=.0|$))", string)
if not sequences:
return 1
# Get the sizes of all these sequences; it is all we need to know
sizes = [len(seq) for seq in sequences]
# Generate Fibonacci numbers up to the maximum needed:
fib = fib_to(max(sizes))
# Take the product of the sizes for each of the sequences
return reduce(mul, [fib[size] for size in sizes], 1)
tests = [ # inputs combined with expected outputs
["", 1],
["2", 1],
["12", 2],
["121", 3],
["1234", 3],
["2121", 5],
["210", 1],
["210210", 1],
["22102210", 4],
["219219", 9],
["07", 0],
["507", 0]
]
for test in tests:
res = get_combination(test[0])
if res != test[1]:
print("Error - Input: '{}' Output: {} Expected: {}".format(test[0], res, test[1]))
else:
print("OK - Input: '{}' Output: {}".format(test[0], res))

注意被测试的边界情况。您的代码未能通过这些测试中的几个。在

在写这篇文章的时候,没有一个答案能为输入“07”生成正确的结果(它应该返回0),而kashif的答案是唯一一个没有通过测试的答案。在

以下是编写时每个答案的测试输出:repl.it