Skip to content

Commit

Permalink
Merge pull request #1 from kristoferfannar/72.EditDistance
Browse files Browse the repository at this point in the history
added golang implementation for edit distance
  • Loading branch information
kristoferfannar authored Mar 22, 2024
2 parents 39ad594 + 0da9a02 commit 5431989
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# mac user here 👋
.DS_Store

.vscode
3 changes: 3 additions & 0 deletions problems/72. Edit Distance/golang/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module editDistance

go 1.22
156 changes: 156 additions & 0 deletions problems/72. Edit Distance/golang/main.go
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()
}

}

0 comments on commit 5431989

Please sign in to comment.