-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from kristoferfannar/72.EditDistance
added golang implementation for edit distance
- Loading branch information
Showing
3 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# mac user here 👋 | ||
.DS_Store | ||
|
||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module editDistance | ||
|
||
go 1.22 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// Top down, recursion style Edit Distance implementation | ||
// While this isn't as fast (and readable) as a simple nested for loop for a bottom up approach | ||
// (ca 4x faster according to minor testing on my side), | ||
// I do feel like it is a cooler implementation. | ||
|
||
// This is my first leetcode problem, | ||
// which I solved to get familiar with the algorithm | ||
// | ||
|
||
// Run with: | ||
// go run . | ||
// go run . "word1" "word2" | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"time" | ||
) | ||
|
||
// visualizer for fun... it may however be broken. For example | ||
// EditDistance("park", "spake") shows: | ||
// |p a r k | ||
// s |1 2 3 0 | ||
// p |1 2 3 0 | ||
// a |2 1 2 0 | ||
// k |3 2 2 2 | ||
// e |4 3 3 3 | ||
// | ||
// which doesn't look correct | ||
|
||
func visualizer(D [][]int, word1, word2 string) { | ||
for y := range len(word2) + 1 { | ||
for x := range len(word1) + 1 { | ||
if y == 0 && x == 0 { | ||
fmt.Printf(" |") | ||
} else if y == 0 { | ||
fmt.Printf("%s ", string(word1[x-1])) | ||
} else if x == 0 { | ||
fmt.Printf("%s |", string(word2[y-1])) | ||
} else { | ||
fmt.Printf("%d ", D[x][y]) | ||
} | ||
if x == len(word1) { | ||
fmt.Println() | ||
} | ||
} | ||
} | ||
} | ||
|
||
func calculate(calc [][]bool, D [][]int, x int, y int, word1 string, word2 string) { | ||
|
||
if x == 0 { | ||
D[x][y] = y | ||
calc[x][y] = true | ||
return | ||
} | ||
|
||
if y == 0 { | ||
D[x][y] = x | ||
calc[x][y] = true | ||
return | ||
} | ||
|
||
if word1[x-1] == word2[y-1] { | ||
lastCalc := calc[x-1][y-1] | ||
if !lastCalc { | ||
calculate(calc, D, x-1, y-1, word1, word2) | ||
} | ||
D[x][y] = D[x-1][y-1] | ||
calc[x][y] = true | ||
return | ||
} | ||
|
||
insertCalc := calc[x][y-1] | ||
if !insertCalc { | ||
calculate(calc, D, x, y-1, word1, word2) | ||
} | ||
insert := D[x][y-1] | ||
|
||
replaceCalc := calc[x-1][y-1] | ||
if !replaceCalc { | ||
calculate(calc, D, x-1, y-1, word1, word2) | ||
} | ||
replace := D[x-1][y-1] | ||
|
||
deleteCalc := calc[x-1][y] | ||
if !deleteCalc { | ||
calculate(calc, D, x-1, y, word1, word2) | ||
} | ||
delete := D[x-1][y] | ||
|
||
D[x][y] = min(insert+1, replace+1, delete+1) | ||
calc[x][y] = true | ||
} | ||
|
||
func EditDistance(word1 string, word2 string) int { | ||
x := len(word1) | ||
y := len(word2) | ||
|
||
if x <= 0 && y <= 0 { | ||
return 0 | ||
} else if x <= 0 || y <= 0 { | ||
return x + y | ||
} | ||
|
||
D := make([][]int, x+1) | ||
calc := make([][]bool, x+1) | ||
|
||
for i := range calc { | ||
calc[i] = make([]bool, y+1) | ||
D[i] = make([]int, y+1) | ||
} | ||
|
||
// visualizer(D, word1, word2) | ||
calculate(calc, D, x, y, word1, word2) | ||
|
||
if len(word1) <= 50 && len(word2) <= 50 { | ||
visualizer(D, word1, word2) | ||
} | ||
return D[x][y] | ||
} | ||
|
||
func tests() { | ||
dna1000_1 := "ggtggttggtcagaaccgtcccgtatgttcataactaggcactagtaccggggccaggacgggagtgcaatagcaagcccttatcaaaaccgtcgcgctaaccacgcaaagatacggtatcacatatgccaagaattggggatgggtattagaatgacctaggtcaacactccttgttagagcgagtggcgtgtgacgtaccacgtcgtacttaactagatcgcttaaagccccgatgtggccacttggaggattcaaaggccctaatgatcctcacacgctaccgaggttgacggcgcttcttgaaaacacaaatttcttggtgacatacgcctacgactcattgtcgtacttttcgtctatcaccaagcgaaacctcccccacttaaccatctatgcgaattgttattcggcaccgccaccgtggaaacccgtcataaaaggaccatgccaaattggtttcatcgacaaagtccattaagttcgatataaacttatttgcagctcgcaagataaaaggctatgtccatgccatgttcggcgcacctctcctcgcgctgtaggacgcaacgttcgttcataatcgagtagtcctgctgcactgatggagccatccattgcagcgtcagcgcttcgactccggcccgctcatcgctagttagctatccgtacagtatcagaacatcttggggcttagtaaagtggtcggatccggtgttttttgcagtagcaaatggtttctaaaaacctgtcggcttttagattttacgatccctcgagtcttcgacttcttcgatcgtcacggtcctaagtgtcttgcgaccaggtatcagtgggcgcgtgcactttttgagttcgaagttagcgagcgtccctagaagtatccaattgcacctgttgaaaggaggaatatcctcaaattttaggaccttttagccttacccatactcgtggtagaagcattcggtcgtcggttagagttccattagtaataaatcgc" | ||
dna1000_2 := "aagtggggcagtggctcacacccatcatttggtgctaggcaatatatggtgaaaattcggtgcgggaagccaatcttgatgcagtcaactaaggtaaggctggcatgactagaaagcgttgacggcactacgtccatacatgcagccagtcgagataagtacttatacggttaccatctatgaaccagaccggatgtaatccagattaaacgggattgggtctttgctttcacccgggcttggttagagacagcaccctttcctgattacacctcgcataaaaccctagattttaggacactggacggtcttttcgcgatgcttttggtgtgcgccggacaaaggttataaatggtgtctctagtgaaggacggtttagtcgatgccaacgtgtatcaatgtagggcacggccggaggtctcgctggtattgcatttcgggatccgatgaatatcgtacgatagtagtgtccacagaacctttgtgtagttatacgcgctgtggtaccgatggccatagccgtagtggtccgctttgtgtgctgcgctacctgccggccctttaagggaacacgtgtaagccagttaactgagttcctaacccccaagagcatcgctccgatgtgttacgtactctcgtcactccagagatgcacgctcgactagtggtctggcagttatcggcttcgtgaagtatcgcaagtcttgacgttggactttgggtattataaccaatgtcgtgacgatatcgtgtcctagcgggctacctacatgcgggcggtaatatcgcgaatggccgcccacaagagtagaatcagttttcgtgtcctccttggttttcctgcatcgaatgttagctaggctgggacatcaatatatgtttcgcgcgtctttggtagcttccactcatctaaacattatcctggcctactgaaagtaatttccagggaccaccaacgggtccctggccgtattacccagcatcgtttctcccaggtcaa" | ||
dna100_1 := dna1000_1[:100] | ||
dna100_2 := dna1000_2[:100] | ||
|
||
start := time.Now() | ||
fmt.Printf("EditDistance(): n = %d | %d", 100, EditDistance(dna100_1, dna100_2)) | ||
end := time.Now() | ||
fmt.Printf(" in %v\n", end.Sub(start)) | ||
|
||
start = time.Now() | ||
fmt.Printf("EditDistance(): n = %d | %d", 1000, EditDistance(dna1000_1, dna1000_2)) | ||
end = time.Now() | ||
fmt.Printf(" in %v\n", end.Sub(start)) | ||
} | ||
|
||
func main() { | ||
if len(os.Args) == 3 { | ||
fmt.Printf("Program arguments %s and %s accepted\n", os.Args[1], os.Args[2]) | ||
word1 := os.Args[1] | ||
word2 := os.Args[2] | ||
|
||
start := time.Now() | ||
fmt.Printf("EditDistance(%s, %s) | %d", word1, word2, EditDistance(word1, word2)) | ||
end := time.Now() | ||
fmt.Printf(" in %v\n", end.Sub(start)) | ||
} else { | ||
tests() | ||
} | ||
|
||
} |