views:

304

answers:

4

I am trying to solve the following problem but cannot find an elegant solution. Any ideas? Thanks.

Input - a variable length string of numbers, e.g., string str = "5557476374202110373551116201";

Task - Check (from left to right) that each number (ignoring the repetitions) does not appear in the following 2 indexes. Using eg. above, First number = 5. Ignoring reps we see that last index of 5 in the group is 2. So we check next 2 indexes, i.e. 3 and 4 should not have 5. If it does we count it as error. Goal is to count such errors in the string.

In the above string errors are at indexes, 3,10 and 16.

+3  A: 

A simple indexed for loop with a couple of look ahead if checks would work. You can treat a string as a char[] or as an IEnumerable - either way you can use that to loop over all of the characters and perform a lookahead check to see if the following one or two characters is a duplicate.

LBushkin
+5  A: 

in addition to the other excellent solutions you can use a simple regexp:

foreach (Match m in Regexp.Matches(str, @"(\d)(?!\1)(?=\d\1)"))
    Console.WriteLine("Error: " + m.Index);

returns 3,10,16. this would match adjacent errors using lookahead with a backreference. handles repetitions. .net should support that. if not, you can use a non-backreference version:

(?<=0[^0])0|(?<=1[^1])1|(?<=2[^2])2|(?<=3[^3])3|(?<=4[^4])4|(?<=5[^5])5|(?<=6[^6])6|(?<=7[^7])7|(?<=8[^8])8|(?<=9[^9])9

jspcal
+1 Man-point for the non-backreference version. Yikes.
ProfK
+2  A: 

Sorry, not a C# man, but here's a simple solution in Ruby:

a="5557476374202110373551116201"
0.upto(a.length) do |i|
  puts "error at #{i}" if a[i]!=a[i+1] && a[i]==a[i+2]
end

Output:

error at 3
error at 10
error at 16
fd
+1  A: 

Here's something I threw together in C# that worked with the example input from the question. I haven't checked it that thoroughly, though...

public static IEnumerable<int> GetErrorIndices(string text) {
    if (string.IsNullOrEmpty(text))
        yield break;

    int i = 0;
    while (i < text.Length) {
        char c = text[i];

        // get the index of the next character that isn't a repetition
        int nextIndex = i + 1;
        while (nextIndex < text.Length && text[nextIndex] == c)
            nextIndex++;

        // if we've reached the end of the string, there's no error
        if (nextIndex + 1 >= text.Length)
            break;

        // we actually only care about text[nextIndex + 1],
        // NOT text[nextIndex] ... why? because text[nextIndex]
        // CAN'T be a repetition (we already skipped to the first
        // non-repetition)
        if (text[nextIndex + 1] == c)
            yield return i;

        i = nextIndex;
    }

    yield break;
}
Dan Tao