【发布时间】:2014-12-08 10:36:10
【问题描述】:
我使用 Hashtbl 存储(int*string*string),这是问题的答案。但是,当我运行时,答案不正确。我认为它跳过了一些值并且没有计算它们。
这是我的代码:
let solve_memo (x:string) (y:string) : (int*string*string) =
let x_len = String.length x in
let y_len = String.length y in
let tbl_size = x_len * y_len in
let tbl = Hashtbl.create tbl_size in
let case1 xi yi =
if x.[xi] = y.[yi] then 1 else -1
in
let choose_max (pt1,strxi,stryi) (pt2,strx2,stry2) (pt3,strx3,stry3) =
if pt1>pt2 then
if pt1>pt3 then (pt1,strxi,stryi)
else (pt3,strx3,stry3)
else
if pt2>pt3 then (pt2,strx2,stry2)
else (pt3,strx3,stry3)
in
let rec aux xi yi (pt,strx,stry) =
if (xi = x_len && yi = y_len) then (pt,strx,stry)
else
if xi = x_len then
(
pt + (-2 * (y_len - yi)),
String.concat "" [strx; String.make (y_len - yi) ' '],
String.concat "" [stry; String.sub y (yi) (y_len - yi)]
)
else if yi = y_len then
(pt + (-2 * (x_len - xi)),
String.concat "" [strx; String.sub x (xi) (x_len - xi)],
String.concat "" [stry; String.make (x_len - xi) ' ']
)
else
try
Hashtbl.find tbl (xi,yi)
with _ ->
let r1 = aux (xi+1) (yi+1) (pt+(case1 xi yi), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; Char.escaped y.[yi]]) in
let r2 = aux (xi+1) yi ((pt-2), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; " "]) in
let r3 = aux xi (yi+1) ((pt-2), String.concat "" [strx; " "] , String.concat "" [stry; Char.escaped y.[yi]]) in
let r = choose_max r1 r2 r3 in
let _ = Hashtbl.add tbl (xi,yi) r in
r
in aux 0 0 (0,"","")
;;
当我打印在 hashtbl 中找到的值时,它会重复 2-3 个可能在迭代开始时创建的值。 谢谢。
添加:
这是原始的简单求解函数,我想添加一个 Hashtbl 以使其更快,但它返回错误的结果
let solve (x:string) (y:string) : (int*string*string) =
let x_len = String.length x in
let y_len = String.length y in
let rec aux xi yi (pt,strx,stry) =
let case1 xi yi =
if x.[xi] = y.[yi] then 1 else -1
in
let choose_max (pt1,strxi,stryi) (pt2,strx2,stry2) (pt3,strx3,stry3) =
if pt1>pt2 then
if pt1>pt3 then (pt1,strxi,stryi)
else (pt3,strx3,stry3)
else
if pt2>pt3 then (pt2,strx2,stry2)
else (pt3,strx3,stry3)
in
if xi = x_len then
(
pt + (-2 * (y_len - yi)),
String.concat "" [strx; String.make (y_len - yi) ' '],
String.concat "" [stry; String.sub y (yi) (y_len - yi)]
)
else if yi = y_len then
(pt + (-2 * (String.length x - xi)),
String.concat "" [strx; String.sub x (xi) (x_len - xi)],
String.concat "" [stry; String.make (x_len - xi) ' ']
)
else
let r1 = aux (xi+1) (yi+1) (pt+(case1 xi yi), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; Char.escaped y.[yi]]) in
let r2 = aux (xi+1) yi ((pt-2), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; " "]) in
let r3 = aux xi (yi+1) ((pt-2), String.concat "" [strx; " "] , String.concat "" [stry; Char.escaped y.[yi]]) in
choose_max r1 r2 r3
in aux 0 0 (0,"","")
;;
【问题讨论】:
-
我想向你保证,OCaml 没有损坏。我们每天都在对其进行测试))尝试重写您的代码,使其至少易于理解。
-
这是解决问题的一种奇怪方法。您应该考虑每个子字符串是一个矩阵,并记住每个子矩阵(子字符串对)的结果。您在矩阵中向前看,而不是向后看子问题。我建议您解决一个单元格,因为邻居已被记忆,然后在 hashtbl 中记忆该结果并返回。有了这个基本的直觉,您可以看到您应该查询包含答案 (x_len,y_len) 的单元格。
-
此外,存储定义对齐方式的对将占用足够大的序列的内存。通过矩阵的回溯是 O(n) 阶,因此不会增加填充成本和对齐方向 (O(n*n)) 的复杂性。
-
虽然,不是您正在寻找的递归解决方案,但回溯算法和成本函数的隔离包含在 phylocaml 项目 (github.com/amnh/phylocaml)alignment.ml 文件中在 FullAlign 模块中。这是功能化的,因此无法满足您的需求,但会为您正在寻找的解决方案的简单性提供一些指导。
-
感谢您的 cmets。我最近才开始学习 OCaml 和函数式编程。我还有很多东西要学。我添加了一些信息,但我会尝试使用您的建议进行修复。
标签: dynamic recursion ocaml dynamic-programming memoization