First a function to calculate the mismatch score, using this spec:
Mismatch(S) is defined as number of corresponding positions were characters are different in S and reverse(S). For example : S = abab, reverse(S) = baba. Number of mismatches = 4. S= abca. Number of mismatches = 2.
We don't need to actually reverse the string. Just compare the first character with the last, then the second with the second last, etc. I find it straightforward to use two index variables for something like this:
int mismatches(String s) {
int result = 0;
int i = 0;
int j = s.length() - 1;
while (j >= 0) {
if (s.charAt(i) != s.charAt(j)) result++;
i++;
j--;
}
return result;
}
And here are some tests to increase our confidence:
@Test
public void test_mismatches() {
assertEquals(0, mismatches(""));
assertEquals(0, mismatches("a"));
assertEquals(0, mismatches("aa"));
assertEquals(2, mismatches("ab"));
assertEquals(0, mismatches("aaa"));
assertEquals(2, mismatches("aab"));
assertEquals(2, mismatches("abc"));
assertEquals(0, mismatches("aaaa"));
assertEquals(2, mismatches("aaab"));
assertEquals(2, mismatches("aaba"));
assertEquals(4, mismatches("abcd"));
}
Now let's find the max mismatch. Here is the spec:
You are given a string S of length N. You can select and reverse any
substring of S of any length. You are allowed to perform this
operation many number of times.
Determine maximum number of mismatches by performing operation.
This is unclear and has typos. It is lazily written and if it was client work, I would be asking for a clarification. I've been burned in the past by working from unclear specs, and building something that the client didn't intend.
I think the use of the word "reverse" is a misnomer. I think it is to help hint at a solution for calculating the mismatch. The spec should be:
You are given a string. Determine maximum number of mismatches from any substring. For clarity, the original string is a valid substring of itself.
With this revised spec, we can just use a nested for loop to traverse the search space:
int maxMismatches(String s) {
int result = 0;
for (int i = 0; i < s.length(); i++)
for (int j = s.length(); j > i; j--) {
int mismatch = mismatches(s.substring(i, j));
if (mismatch > result)
result = mismatch;
}
return result;
}
And some tests:
@Test
public void test_max_mismatches() {
assertEquals(0, maxMismatches(""));
assertEquals(0, maxMismatches("a"));
assertEquals(0, maxMismatches("aa"));
assertEquals(2, maxMismatches("ab"));
assertEquals(2, maxMismatches("aba"));
assertEquals(4, maxMismatches("aabbaa"));
assertEquals(6, maxMismatches("aaabcda"));
}
There is a gap in this set of tests. Some of the test strings require truncating the start to find the max. Some require truncating the end, but none require truncating both the start and end.
Both functions have obvious optimisations but they reduce clarity in a scenario where I don't think performance is important.