我看到了以下无法解决的问题。什么样的算法会解决它?
我们得到了一个正整数n。设A是长度为n的所有可能字符串的集合,其中字符来自集合{1,2,3,4,5,6},即掷骰子n次的结果。 A的多少个元素包含以下字符串中的至少一个作为子字符串:
1, 2, 3, 4, 5, 6
1, 1, 2, 2, 3, 3
4, 4, 5, 5, 6, 6
1, 1, 1, 2, 2, 2
3, 3, 3, 4, 4, 4
5, 5, 5, 6, 6, 6
1, 1, 1, 1, 1, 1
2, 2, 2, 2, 2, 2
3, 3, 3, 3, 3, 3
4, 4, 4, 4, 4, 4
5, 5, 5, 5, 5, 5
6, 6, 6, 6, 6, 6
我想知道某种递归方法,但当我试图解决问题时,我只是弄得一团糟。
答案 0 :(得分:1)
我建议您阅读Aho-Corasick algorithm。这基于一组字符串构造有限状态机。 (如果你的字符串列表是固定的,你甚至可以手工完成。)
一旦你有一个有限状态机(大约有70个状态),你应该添加一个额外的吸收状态来标记何时检测到任何字符串。
现在你的问题被减少到找到6 ** n个字符串中有多少在被推进状态机后最终处于吸收状态。
您可以通过将状态机表示为矩阵来完成此操作。条目M [i,j]表示当添加一个字母时从状态j到达状态i的方式的数量。
最后,计算应用于输入向量的幂n的矩阵,除了对应于初始状态的位置中的1之外,该输入向量全为零。吸收状态位置的数字将告诉您字符串的总数。
(您可以使用标准matrix exponentiation algorithm在O(登录)时间内生成此答案。)
答案 1 :(得分:0)
你的递归方法出了什么问题,你能详细说明一下,无论如何这可以用O(6 ^ n)中的递归方法解决,但是可以使用dp进行优化,使用你只需要跟踪的事实最后6个元素,所以它可以用O(6 * 2 ^ 6 * n)和dp完成。
// ===== OPTION 1 =====
// Pattern matching separated out, lazy eval.
let Foo x =
let valueOne = lazy //... lots of code, evaluated on Force().
let valueTwo = lazy //... lots of code, evaluated on Force().
match x with
| 1 -> valueOne.Force()
| 2 -> valueTwo.Force()
// ===== OPTION 2 =====
// Pattern matching separated out, with arguments.
let Foo x =
let valueOne a = //... lots of code.
let valueTwo a = //... lots of code.
match x with
| 1 -> valueOne x
| 2 -> valueTwo x
// ===== OPTION 3 =====
// Active Pattern matching separated out, with arguments.
let Foo x =
let (|ValueOne|_|) inp =
if inp = 1 then Some(...) else None
let (|ValueTwo|_|) inp =
if inp = 2 then Some(...) else None
match x with
| ValueOne a -> a
| ValueTwo b -> b