你得到一个长整型数N(小于2^63-1)和50个其他整数。你需要找出从1到N中有多少个数字不包含这50个整数作为子串?
这是一道面试题目。
你得到一个长整型数N(小于2^63-1)和50个其他整数。你需要找出从1到N中有多少个数字不包含这50个整数作为子串?
这是一道面试题目。
您没有指定进制,但我会假设十进制而不失一般性。
首先,请认识到这是一个字符串问题,而不是数字问题。
构建一个有限自动机A来识别50个整数作为其他字符串的子字符串。例如,两个整数44和3可以通过以下正则表达式识别为子字符串:
^.*(44|3).*$
构建一个有限自动机B来识别所有小于N的数字。例如,在十进制中识别1到27(包括27),可以通过编译RE实现
^([1-9]|1[0-9]|2[0-7])$
计算自动机 A 和 B 的交集 C,它也是一个有限自动机。
使用动态编程算法计算被C识别的语言的大小。用相同的算法计算被A识别的语言的大小,并将其从中减去。
(我并不声称这是渐近最优的,但它足以快速解决许多欧拉项目问题 :)
S1: {A} # start
S2: {A, B}
S3: {A, C}
S4: {A, B, C}
S5: matched
以下是转换规则:
S1:
3: S3
4: S2
end of string: FAIL
any other char: S1
S2:
3: S3
4: S3
end of string: FAIL
any other char: S1
S3:
4: S4
end of string: S5 (match)
any other char: S3
S4:
end of string: S5 (match)
any other char: S4
S1
开始,并遵循规则,您将匹配该模式。这个过程可能会很长而繁琐,但幸运的是可以自动化。我猜larsmans已经为自己的使用自动化了它。(技术说明:从“RE中的位置”扩展到“可能处于的位置集合”的过程可以在前期或运行时完成。对于大多数RE来说,最好在前期完成,就像这里一样。但是微小部分的病态示例将得到非常多的状态,最好在运行时完成。)^([1-9]|1[0-9]|2[0-7])$
可以标记为:^
A([1-9]|1
B[0-9]|2
C[0-7])
D$
,并且我们得到以下状态:T1: {A}
T2: {D}
T3: {B, D}
T4: {C, D}
转换和过渡效果:
T1:
1: T3
2: T4
3-9: T2
any other char: FAIL
T2:
end of string: MATCH
any other char: FAIL
T3:
0-9: T2
end of string: MATCH
any other char: FAIL
T4:
0-7: T2
end of string: MATCH
any other char: FAIL
state: (S1, T1) next char: 1
state: (S1, T3) next char: 3
state: (S3, T2) next char: end of string
state: (matched, matched) -> matched
接着在数字14
上进行操作。
state: (S1, T1) next char: 1
state: (S1, T3) next char: 4
state: (S2, T2) next char: end of string
state: (FAIL, matched) -> FAIL
0 chars:
(S1, T1): 1
-> (S1, T3): 1 # 1
-> (S1, T4): 1 # 2
-> (S3, T2): 1 # 3
-> (S2, T2): 1 # 4
-> (S1, T2): 5 # 5-9
1 chars:
(S1: T2): 5 # dead end
(S1, T3): 1
-> (S1, T2): 8 # 0-2, 5-9
-> (S2, T2): 1 # 3
-> (S3, T2): 1 # 4
(S1, T4): 1
-> (S1, T2): 6 # 0-2, 5-7
-> (S2, T2): 1 # 3
-> (S3, T2): 1 # 4
(S2, T2): 1 # dead end
(S3, T2): 1
-> match: 1 # end of string
2 chars:
(S1, T2): 14 # dead end
(S2, T2): 2 # dead end
(S3, T2): 2
-> match 2 # end of string
match: 1
-> match 1 # carry through the count
3 chars:
match: 3
好的,这是很多工作,但我们发现有3个字符串同时符合这两条规则。而且我们以一种可自动化和可扩展到更大数量的方式完成了它。
当然,我们最初提出的问题是有多少个匹配第二个规则但不匹配第一个规则。我们知道有27个符合第二个规则,3个符合两个规则,因此有24个必须符合第二个规则但不符合第一个规则。
正如我之前所说,这只是larsmans的解决方案阐述。如果你学到了东西,请为他点赞,投票支持他的答案。如果这些材料听起来有趣,请购买像《程序语言实践》这样的书籍,学习更多关于有限自动机、解析、编译等方面的知识。这是一个非常好的技能集,很多程序员都没有掌握。