Skip to content

Commit 5431989

Browse files
Merge pull request #1 from kristoferfannar/72.EditDistance
added golang implementation for edit distance
2 parents 39ad594 + 0da9a02 commit 5431989

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# mac user here 👋
2+
.DS_Store
3+
4+
.vscode
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module editDistance
2+
3+
go 1.22
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Top down, recursion style Edit Distance implementation
2+
// While this isn't as fast (and readable) as a simple nested for loop for a bottom up approach
3+
// (ca 4x faster according to minor testing on my side),
4+
// I do feel like it is a cooler implementation.
5+
6+
// This is my first leetcode problem,
7+
// which I solved to get familiar with the algorithm
8+
//
9+
10+
// Run with:
11+
// go run .
12+
// go run . "word1" "word2"
13+
14+
package main
15+
16+
import (
17+
"fmt"
18+
"os"
19+
"time"
20+
)
21+
22+
// visualizer for fun... it may however be broken. For example
23+
// EditDistance("park", "spake") shows:
24+
// |p a r k
25+
// s |1 2 3 0
26+
// p |1 2 3 0
27+
// a |2 1 2 0
28+
// k |3 2 2 2
29+
// e |4 3 3 3
30+
//
31+
// which doesn't look correct
32+
33+
func visualizer(D [][]int, word1, word2 string) {
34+
for y := range len(word2) + 1 {
35+
for x := range len(word1) + 1 {
36+
if y == 0 && x == 0 {
37+
fmt.Printf(" |")
38+
} else if y == 0 {
39+
fmt.Printf("%s ", string(word1[x-1]))
40+
} else if x == 0 {
41+
fmt.Printf("%s |", string(word2[y-1]))
42+
} else {
43+
fmt.Printf("%d ", D[x][y])
44+
}
45+
if x == len(word1) {
46+
fmt.Println()
47+
}
48+
}
49+
}
50+
}
51+
52+
func calculate(calc [][]bool, D [][]int, x int, y int, word1 string, word2 string) {
53+
54+
if x == 0 {
55+
D[x][y] = y
56+
calc[x][y] = true
57+
return
58+
}
59+
60+
if y == 0 {
61+
D[x][y] = x
62+
calc[x][y] = true
63+
return
64+
}
65+
66+
if word1[x-1] == word2[y-1] {
67+
lastCalc := calc[x-1][y-1]
68+
if !lastCalc {
69+
calculate(calc, D, x-1, y-1, word1, word2)
70+
}
71+
D[x][y] = D[x-1][y-1]
72+
calc[x][y] = true
73+
return
74+
}
75+
76+
insertCalc := calc[x][y-1]
77+
if !insertCalc {
78+
calculate(calc, D, x, y-1, word1, word2)
79+
}
80+
insert := D[x][y-1]
81+
82+
replaceCalc := calc[x-1][y-1]
83+
if !replaceCalc {
84+
calculate(calc, D, x-1, y-1, word1, word2)
85+
}
86+
replace := D[x-1][y-1]
87+
88+
deleteCalc := calc[x-1][y]
89+
if !deleteCalc {
90+
calculate(calc, D, x-1, y, word1, word2)
91+
}
92+
delete := D[x-1][y]
93+
94+
D[x][y] = min(insert+1, replace+1, delete+1)
95+
calc[x][y] = true
96+
}
97+
98+
func EditDistance(word1 string, word2 string) int {
99+
x := len(word1)
100+
y := len(word2)
101+
102+
if x <= 0 && y <= 0 {
103+
return 0
104+
} else if x <= 0 || y <= 0 {
105+
return x + y
106+
}
107+
108+
D := make([][]int, x+1)
109+
calc := make([][]bool, x+1)
110+
111+
for i := range calc {
112+
calc[i] = make([]bool, y+1)
113+
D[i] = make([]int, y+1)
114+
}
115+
116+
// visualizer(D, word1, word2)
117+
calculate(calc, D, x, y, word1, word2)
118+
119+
if len(word1) <= 50 && len(word2) <= 50 {
120+
visualizer(D, word1, word2)
121+
}
122+
return D[x][y]
123+
}
124+
125+
func tests() {
126+
dna1000_1 := "ggtggttggtcagaaccgtcccgtatgttcataactaggcactagtaccggggccaggacgggagtgcaatagcaagcccttatcaaaaccgtcgcgctaaccacgcaaagatacggtatcacatatgccaagaattggggatgggtattagaatgacctaggtcaacactccttgttagagcgagtggcgtgtgacgtaccacgtcgtacttaactagatcgcttaaagccccgatgtggccacttggaggattcaaaggccctaatgatcctcacacgctaccgaggttgacggcgcttcttgaaaacacaaatttcttggtgacatacgcctacgactcattgtcgtacttttcgtctatcaccaagcgaaacctcccccacttaaccatctatgcgaattgttattcggcaccgccaccgtggaaacccgtcataaaaggaccatgccaaattggtttcatcgacaaagtccattaagttcgatataaacttatttgcagctcgcaagataaaaggctatgtccatgccatgttcggcgcacctctcctcgcgctgtaggacgcaacgttcgttcataatcgagtagtcctgctgcactgatggagccatccattgcagcgtcagcgcttcgactccggcccgctcatcgctagttagctatccgtacagtatcagaacatcttggggcttagtaaagtggtcggatccggtgttttttgcagtagcaaatggtttctaaaaacctgtcggcttttagattttacgatccctcgagtcttcgacttcttcgatcgtcacggtcctaagtgtcttgcgaccaggtatcagtgggcgcgtgcactttttgagttcgaagttagcgagcgtccctagaagtatccaattgcacctgttgaaaggaggaatatcctcaaattttaggaccttttagccttacccatactcgtggtagaagcattcggtcgtcggttagagttccattagtaataaatcgc"
127+
dna1000_2 := "aagtggggcagtggctcacacccatcatttggtgctaggcaatatatggtgaaaattcggtgcgggaagccaatcttgatgcagtcaactaaggtaaggctggcatgactagaaagcgttgacggcactacgtccatacatgcagccagtcgagataagtacttatacggttaccatctatgaaccagaccggatgtaatccagattaaacgggattgggtctttgctttcacccgggcttggttagagacagcaccctttcctgattacacctcgcataaaaccctagattttaggacactggacggtcttttcgcgatgcttttggtgtgcgccggacaaaggttataaatggtgtctctagtgaaggacggtttagtcgatgccaacgtgtatcaatgtagggcacggccggaggtctcgctggtattgcatttcgggatccgatgaatatcgtacgatagtagtgtccacagaacctttgtgtagttatacgcgctgtggtaccgatggccatagccgtagtggtccgctttgtgtgctgcgctacctgccggccctttaagggaacacgtgtaagccagttaactgagttcctaacccccaagagcatcgctccgatgtgttacgtactctcgtcactccagagatgcacgctcgactagtggtctggcagttatcggcttcgtgaagtatcgcaagtcttgacgttggactttgggtattataaccaatgtcgtgacgatatcgtgtcctagcgggctacctacatgcgggcggtaatatcgcgaatggccgcccacaagagtagaatcagttttcgtgtcctccttggttttcctgcatcgaatgttagctaggctgggacatcaatatatgtttcgcgcgtctttggtagcttccactcatctaaacattatcctggcctactgaaagtaatttccagggaccaccaacgggtccctggccgtattacccagcatcgtttctcccaggtcaa"
128+
dna100_1 := dna1000_1[:100]
129+
dna100_2 := dna1000_2[:100]
130+
131+
start := time.Now()
132+
fmt.Printf("EditDistance(): n = %d | %d", 100, EditDistance(dna100_1, dna100_2))
133+
end := time.Now()
134+
fmt.Printf(" in %v\n", end.Sub(start))
135+
136+
start = time.Now()
137+
fmt.Printf("EditDistance(): n = %d | %d", 1000, EditDistance(dna1000_1, dna1000_2))
138+
end = time.Now()
139+
fmt.Printf(" in %v\n", end.Sub(start))
140+
}
141+
142+
func main() {
143+
if len(os.Args) == 3 {
144+
fmt.Printf("Program arguments %s and %s accepted\n", os.Args[1], os.Args[2])
145+
word1 := os.Args[1]
146+
word2 := os.Args[2]
147+
148+
start := time.Now()
149+
fmt.Printf("EditDistance(%s, %s) | %d", word1, word2, EditDistance(word1, word2))
150+
end := time.Now()
151+
fmt.Printf(" in %v\n", end.Sub(start))
152+
} else {
153+
tests()
154+
}
155+
156+
}

0 commit comments

Comments
 (0)