这是使用Clojure进行递归的最小Levenshtein(编辑距离)实现:
(defn levenshtein [s1, i1, s2, i2]
(cond
(= 0 i1) i2
(= 0 i2) i1
:else
(min (+ (levenshtein s1 (- i1 1) s2 i2) 1)
(+ (levenshtein s1 i1 s2 (- i2 1)) 1)
(+ (levenshtein s1 (- i1 1) s2 (- i2 1)) (if (= (subs s1 i1 (+ i1 1)) (subs s2 i2 (+ i2 1))) 0 1))
)
)
)
(defn levenshteinSimple [s1, s2]
(levenshtein s1, (- (count s1) 1), s2, (- (count s2) 1)))
可以这样使用:
(println (levenshteinSimple "hello", "hilloo"))
(println (levenshteinSimple "hello", "hilloo"))
(println (levenshteinSimple "bananas", "bananas"))
(println (levenshteinSimple "ananas", "bananas"))
打印出来:
2
2
0
1
如何在此实现中添加memoize以提高性能?
请注意:我是Clojure的初学者。这些是我在Clojure中的第一行
答案 0 :(得分:1)
最简单的方法是使用memoize
函数。它需要一个函数,并返回一个memoized函数:
(let [mem-lev (memoize levenshteinSimple]
(println (mem-lev "hello", "hilloo"))
(println (mem-lev "hello", "hilloo"))
(println (mem-lev "bananas", "bananas"))
(println (mem-lev "ananas", "bananas")))
mem-lev
会记住你给它的每个参数以及你的函数返回的结果,如果它已经看到你给它的参数,它将返回缓存的结果。
请注意,这将 not 导致递归调用变为memoized,但任何递归调用都不太可能从memoization中受益。
这也不导致您的原始功能被记忆。在此示例中,只会记住mem-lev
。如果确实想要记住您的全局函数,您可以将定义更改为:
(def levenshteinSimple
(memoize
(fn [s1, s2]
...
但我不建议这样做。这导致函数本身保持状态,这不是理想的。它还会在程序长度上保持该状态,如果被滥用,可能会导致内存问题。
(作为一个很好的练习,尝试编写自己的memoize
版本。通过这样做我学到了很多东西)。