Write a program that can calculate the Hamming difference between two DNA strands.
GAGCCTACTAACGGGAT CATCGTAATGACGGCCT ^ ^ ^ ^ ^ ^^
The Hamming distance between these two DNA strands is 7.
import java.util.Optional;
public class Hamming {
public static int compute(String s1, String s2) {
validateInputs(s1, s2);
int hammingDistance = 0;
int stringLength = s1.length();
for (int i = 0; i < stringLength; i++) {
if (s1.charAt(i) != s2.charAt(i)) {
hammingDistance++;
}
}
return hammingDistance;
}
private static void validateInputs(String s1, String s2) {
if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}
}
}
Test suite:
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
public class HammingTest {
@Test
public void testNoDifferenceBetweenIdenticalStrands() {
assertThat(Hamming.compute("A", "A"), is(0));
}
@Test
public void testCompleteHammingDistanceOfForSingleNucleotideStrand() {
assertThat(Hamming.compute("A", "G"), is(1));
}
@Test
public void testCompleteHammingDistanceForSmallStrand() {
assertThat(Hamming.compute("AG", "CT"), is(2));
}
@Test
public void testSmallHammingDistance() {
assertThat(Hamming.compute("AT", "CT"), is(1));
}
@Test
public void testSmallHammingDistanceInLongerStrand() {
assertThat(Hamming.compute("GGACG", "GGTCG"), is(1));
}
@Test(expected = IllegalArgumentException.class)
public void testValidatesFirstStrandNotLonger() {
Hamming.compute("AAAG", "AAA");
}
@Test(expected = IllegalArgumentException.class)
public void testValidatesOtherStrandNotLonger() {
Hamming.compute("AAA", "AAAG");
}
@Test
public void testLargeHammingDistance() {
assertThat(Hamming.compute("GATACA", "GCATAA"), is(4));
}
@Test
public void testHammingDistanceInVeryLongStrand() {
assertThat(Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT"), is(9));
}
}
Questions:
- Am I using the correct data structures?
- Can I improve performance? Right now it seems to be \$Θ(n)\$ since it has to check all the characters in the string.