module leveshtein.Main
open System
open System.Collections .Generic
let chars = [ | 'a' ..'z' | ]
let Levenshtein ( a: array< char> ) ( b: array< char> ) =
let cache = Dictionary< _, _> ( )
let rec lev i j =
if cache.ContainsKey ( i, j) then cache.[ i, j]
else
let x =
match i, j with
| 0 , j -> j
| i, 0 -> i
| _, _ -> min ( min ( lev ( i - 1 ) j + 1 ) ( lev i ( j - 1 ) + 1 ) ) ( lev ( i - 1 ) ( j - 1 ) + ( if a.[ i - 1 ] = b.[ j - 1 ] then 0 else 1 ) )
cache.Add ( ( i, j) , x)
x
in lev a.Length b.Length
let add i c a = Seq.concat [ Seq.take i a; Seq.singleton c; Seq.skip i a] |> Seq.toArray
let delete i a = Seq.concat [ Seq.take i a; Seq.skip ( i + 1 ) a] |> Seq.toArray
let change i c a = Seq.concat [ Seq.take i a; Seq.singleton c; Seq.skip ( i + 1 ) a] |> Seq.toArray
type Tree< 'a> = Nil | Tree of ' a * list< Tree< 'a>>
/// Creates a tree with all the Levenshtein minimum paths from a to b
let EditChain a b =
let rec generate a =
let d = Levenshtein a b
let gens = seq {
for i in 0..(a.Length - 1) do
let c1 = delete i a
if (Levenshtein c1 b) < d then yield c1 else ()
for c in chars do
let c2 = change i c a
if (Levenshtein c2 b) < d then yield c2 else ()
for i in 0..(a.Length) do
for c in chars do
let c3 = add i c a
if (Levenshtein c3 b) < d then yield c3 else ()
}
gens
|> Seq.map (fun g -> Tree(g, generate g)) |> Seq.toList
let c = generate a
in Tree(a, c)
/// Flattens a Tree giving a list of all the paths from the root to the leaves
let rec Flatten = function
| Nil -> [[]]
| Tree(a, []) -> [[a]]
| Tree(a, ts) ->
let ts2 = ts |> List.map (fun t -> Flatten t) |> List.concat
in ts2 |> List.map (fun t -> a::t)
/// Prints the edit chain paths given by Flatten
let PrettyPrint (t: char array list list) =
let pca (a: char array) = new System.String(a)
t |> List.iter (fun cw ->
printf "%s" (pca (List.head cw))
(List.tail cw) |> List.iter (fun w -> printf " -> %s" (pca w))
printfn "")
[<EntryPoint>]
let main args =
let a = Console.ReadLine().ToCharArray()
let b = Console.ReadLine().ToCharArray()
PrettyPrint (Flatten (EditChain a b))
0
Cm1vZHVsZSBsZXZlc2h0ZWluLk1haW4KIApvcGVuIFN5c3RlbQpvcGVuIFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljIAogCmxldCBjaGFycyA9IFt8J2EnLi4neid8XQogCmxldCBMZXZlbnNodGVpbiAoYTogYXJyYXk8Y2hhcj4pIChiOiBhcnJheTxjaGFyPikgPQogICAgbGV0IGNhY2hlID0gRGljdGlvbmFyeTxfLCBfPigpCiAgICBsZXQgcmVjIGxldiBpIGogPQogICAgICAgIGlmIGNhY2hlLkNvbnRhaW5zS2V5KGksIGopIHRoZW4gY2FjaGUuW2ksIGpdCiAgICAgICAgZWxzZQogICAgICAgICAgICBsZXQgeCA9CiAgICAgICAgICAgICAgICBtYXRjaCBpLCBqIHdpdGgKICAgICAgICAgICAgICAgIHwgMCwgaiAtPiBqCiAgICAgICAgICAgICAgICB8IGksIDAgLT4gaQogICAgICAgICAgICAgICAgfCBfLCBfIC0+IG1pbiAobWluIChsZXYgKGkgLSAxKSBqICsgMSkgKGxldiBpIChqIC0gMSkgKyAxKSkgKGxldiAoaSAtIDEpIChqIC0gMSkgKyAoaWYgYS5baSAtIDFdID0gYi5baiAtIDFdIHRoZW4gMCBlbHNlIDEpKQogICAgICAgICAgICBjYWNoZS5BZGQoKGksIGopLCB4KQogICAgICAgICAgICB4CiAgICBpbiBsZXYgYS5MZW5ndGggYi5MZW5ndGgKIApsZXQgYWRkIGkgYyBhID0gU2VxLmNvbmNhdCBbU2VxLnRha2UgaSBhOyBTZXEuc2luZ2xldG9uIGM7IFNlcS5za2lwIGkgYV0gfD4gU2VxLnRvQXJyYXkKICAgIApsZXQgZGVsZXRlIGkgYSA9IFNlcS5jb25jYXQgW1NlcS50YWtlIGkgYTsgU2VxLnNraXAgKGkgKyAxKSBhXSB8PiBTZXEudG9BcnJheQogICAgCmxldCBjaGFuZ2UgaSBjIGEgPSBTZXEuY29uY2F0IFtTZXEudGFrZSBpIGE7IFNlcS5zaW5nbGV0b24gYzsgU2VxLnNraXAgKGkgKyAxKSBhXSB8PiBTZXEudG9BcnJheQogCnR5cGUgVHJlZTwnYT4gPSBOaWwgfCBUcmVlIG9mICdhICogbGlzdDxUcmVlPCdhPj4KCi8vLyBDcmVhdGVzIGEgdHJlZSB3aXRoIGFsbCB0aGUgTGV2ZW5zaHRlaW4gbWluaW11bSBwYXRocyBmcm9tIGEgdG8gYgpsZXQgRWRpdENoYWluIGEgYiA9CiAgICBsZXQgcmVjIGdlbmVyYXRlIGEgPQogICAgICAgIGxldCBkID0gTGV2ZW5zaHRlaW4gYSBiCiAgICAgICAgbGV0IGdlbnMgPSBzZXEgewogICAgICAgICAgICBmb3IgaSBpbiAwLi4oYS5MZW5ndGggLSAxKSBkbwogICAgICAgICAgICAgICAgbGV0IGMxID0gZGVsZXRlIGkgYQogICAgICAgICAgICAgICAgaWYgKExldmVuc2h0ZWluIGMxIGIpIDwgZCB0aGVuIHlpZWxkIGMxIGVsc2UgKCkKICAgICAgICAgICAgICAgIGZvciBjIGluIGNoYXJzIGRvCiAgICAgICAgICAgICAgICAgICAgbGV0IGMyID0gY2hhbmdlIGkgYyBhCiAgICAgICAgICAgICAgICAgICAgaWYgKExldmVuc2h0ZWluIGMyIGIpIDwgZCB0aGVuIHlpZWxkIGMyIGVsc2UgKCkKICAgICAgICAgICAgZm9yIGkgaW4gMC4uKGEuTGVuZ3RoKSBkbwogICAgICAgICAgICAgICAgZm9yIGMgaW4gY2hhcnMgZG8KICAgICAgICAgICAgICAgICAgICBsZXQgYzMgPSBhZGQgaSBjIGEKICAgICAgICAgICAgICAgICAgICBpZiAoTGV2ZW5zaHRlaW4gYzMgYikgPCBkIHRoZW4geWllbGQgYzMgZWxzZSAoKQogICAgICAgIH0KICAgICAgICBnZW5zCiAgICAgICAgfD4gU2VxLm1hcCAoZnVuIGcgLT4gVHJlZShnLCBnZW5lcmF0ZSBnKSkgfD4gU2VxLnRvTGlzdCAgICAKICAgIGxldCBjID0gZ2VuZXJhdGUgYQogICAgaW4gVHJlZShhLCBjKSAKCi8vLyBGbGF0dGVucyBhIFRyZWUgZ2l2aW5nIGEgbGlzdCBvZiBhbGwgdGhlIHBhdGhzIGZyb20gdGhlIHJvb3QgdG8gdGhlIGxlYXZlcwpsZXQgcmVjIEZsYXR0ZW4gPSBmdW5jdGlvbgogICAgfCBOaWwgLT4gW1tdXQogICAgfCBUcmVlKGEsIFtdKSAtPiBbW2FdXQogICAgfCBUcmVlKGEsIHRzKSAtPgogICAgICAgIGxldCB0czIgPSB0cyB8PiBMaXN0Lm1hcCAoZnVuIHQgLT4gRmxhdHRlbiB0KSB8PiBMaXN0LmNvbmNhdAogICAgICAgIGluIHRzMiB8PiBMaXN0Lm1hcCAoZnVuIHQgLT4gYTo6dCkKCi8vLyBQcmludHMgdGhlIGVkaXQgY2hhaW4gcGF0aHMgZ2l2ZW4gYnkgRmxhdHRlbgpsZXQgUHJldHR5UHJpbnQgKHQ6IGNoYXIgYXJyYXkgbGlzdCBsaXN0KSA9CiAgICBsZXQgcGNhIChhOiBjaGFyIGFycmF5KSA9IG5ldyBTeXN0ZW0uU3RyaW5nKGEpCiAgICB0IHw+IExpc3QuaXRlciAoZnVuIGN3IC0+CiAgICAgICAgcHJpbnRmICIlcyIgKHBjYSAoTGlzdC5oZWFkIGN3KSkKICAgICAgICAoTGlzdC50YWlsIGN3KSB8PiBMaXN0Lml0ZXIgKGZ1biB3IC0+IHByaW50ZiAiIC0+ICVzIiAocGNhIHcpKQogICAgICAgIHByaW50Zm4gIiIpCiAgICAgICAgICAgICAgICAgICAgCls8RW50cnlQb2ludD5dCmxldCBtYWluIGFyZ3MgPQogICAgbGV0IGEgPSBDb25zb2xlLlJlYWRMaW5lKCkuVG9DaGFyQXJyYXkoKSAKICAgIGxldCBiID0gQ29uc29sZS5SZWFkTGluZSgpLlRvQ2hhckFycmF5KCkKICAgIFByZXR0eVByaW50IChGbGF0dGVuIChFZGl0Q2hhaW4gYSBiKSkgICAKICAgIDA=