aboutsummaryrefslogtreecommitdiff
path: root/challenge-096/paulo-custodio/basic/ch-2.bas
blob: 8d88019f32f86d9e5187edba52e5ff66a059f41c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
' Challenge 096
'
' TASK #2 › Edit Distance
' Submitted by: Mohammad S Anwar
' You are given two strings $S1 and $S2.
'
' Write a script to find out the minimum operations required to convert $S1
' into $S2. The operations can be insert, remove or replace a character. Please
' check out Wikipedia page for more information.
'
' Example 1:
' Input: $S1 = "kitten"; $S2 = "sitting"
' Output: 3
'
' Operation 1: replace 'k' with 's'
' Operation 2: replace 'e' with 'i'
' Operation 3: insert 'g' at the end
' Example 2:
' Input: $S1 = "sunday"; $S2 = "monday"
' Output: 2
'
' Operation 1: replace 's' with 'm'
' Operation 2: replace 'u' with 'o'
'
' NOTE: the  Wagner-Fischer Distance algorithm builds a table of distances
'       from which the operations can be deduced

const E as integer = 1
const S as integer = 2
const SE as integer = 3

function min(a as integer, b as integer) as integer
    if a < b then
        min = a
    else
        min = b
    end if
end function

function min3(a as integer, b as integer, c as integer) as integer
    min3 = min(a, min(b, c))
end function

sub wag_fish_dist(a as string, b as string)
    dim i as integer, j as integer, stp as integer, subst_cost as integer
    dim min_dr as integer, min_delta as integer, dr as integer, delta as integer

    ' define a table where d(i,j) is the Levenshtein distance between
    ' first i chars of a and first j chars of b
    dim d(len(a)+1, len(b)+1) as integer

    ' source prefixes can be transformed into empty string by dropping chars
    for i = 1 to len(a)
        d(i,0) = i
    next i

    ' target prefixes can be reached from empty source prefix by inserting chars
    for j = 1 to len(b)
        d(0,j) = j
    next j

    ' flood-fill the rest of the table
    for j = 1 to len(b)
        for i = 1 to len(a)
            if mid(a,i,1) = mid(b,j,1) then
                subst_cost = 0
            else
                subst_cost = 1
            end if
            d(i,j) = min3(d(i-1,j)+1,           _   ' deletion
                          d(i,j-1)+1,           _   ' insertion
                          d(i-1,j-1)+subst_cost)    ' substitution
        next i
    next j

    ' distance is in lower bottom cell
    print trim(str(d(len(a),len(b))))

    ' traverse the minimum path
    i = 0: j = 0
    do while i < len(a) or j < len(b)
        dr = 0: delta = 0: min_dr = 0: min_delta = len(a)+len(b)

        ' search shortest path in priority SE, E, S
        if i < len(a) and j < len(b) then
            dr = SE: delta = d(i+1,j+1) - d(i,j)
            min_dr = dr: min_delta = delta
        end if
        if j < len(b) then
            dr = E: delta = d(i,j+1) - d(i,j)
            if delta < min_delta then
                min_dr = dr: min_delta = delta
            end if
        end if
        if i < len(a) then
            dr = S: delta = d(i+1,j) - d(i,j)
            if delta < min_delta then
                min_dr = dr: min_delta = delta
            end if
        end if

        ' apply shortest path and show steps
        select case min_dr
        case SE
            i += 1: j += 1
            if mid(a,i,1) <> mid(b,j,1) then
                stp += 1
                print "Operation"; stp; ": replace '"; _
                      mid(a,i,1); "' with '"; mid(b,j,1); "'"
            end if
        case E
            j += 1
            stp += 1
            if j = len(b) then
                print "Operation"; stp; ": insert '"; _
                      mid(b,j,1); "' at end"
            else
                print "Operation"; stp; ": insert '"; _
                      mid(b,j,1); "' at position"; j
            end if
        case S
            i += 1
            stp += 1
            if i = len(a) then
                print "Operation"; stp; ": insert '"; _
                      mid(a,i,1); "' at end"
            else
                print "Operation"; stp; ": insert '"; _
                      mid(a,i,1); "' at position"; i
            end if
        case else
            assert(false)
        end select
    loop
end sub


wag_fish_dist command(1), command(2)