DEV Community

Simon Green
Simon Green

Posted on

Weekly Challenge: A good question

Weekly Challenge 328

Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Replace all question marks

Task

You are given a string containing only lower case English letters and ?.

Write a script to replace all ? in the given string so that the string doesn't contain consecutive repeating characters.

My solution

For this one, I will start with the Perl solution. Strings in Perl are mutable (i.e. they can change). For this task, I loop through the position of each character with the variable idx, and assign the char variable to the character at that position.

sub main ($input_string) {
    my $solution = $input_string;
    foreach my $idx ( 0 .. length($solution) - 1 ) {
        my $char = substr( $solution, $idx, 1 );
        if ( $char ne '?' ) {
            next;
        }
Enter fullscreen mode Exit fullscreen mode

If char is not ?, I move onto the next character. I then have an hash called %letters. If idx is not 0 (i.e. the first character), I add the preceding character to the letters hash. If idx isn't the last character's position, I add the following character to the letters hash. The letters hash now has the preceding and following character.

        my %letters = ();
        if ( $idx > 0 ) {
            $letters{ substr( $solution, $idx - 1, 1 ) } = 1;
        }
        if ( $idx < length($solution) - 1 ) {
            $letters{ substr( $solution, $idx + 1, 1 ) } = 1;
        }
Enter fullscreen mode Exit fullscreen mode

The last step to is replace the question mark with a letter, using the following rules.

  1. If letters does not have an a, replace it with a.
  2. If letters does not have an b, replace it with b.
  3. Replace it with c.
        if ( not exists $letters{'a'} ) {
            substr( $solution, $idx, 1 ) = 'a';
        }
        elsif ( not exists $letters{'b'} ) {
            substr( $solution, $idx, 1 ) = 'b';
        }
        else {
            substr( $solution, $idx, 1 ) = 'c';
        }
    }

    say '"', $solution, '"';
}
Enter fullscreen mode Exit fullscreen mode

The Python solution uses the same logic, but builds the solution value letter by letter. In Python, strings are immutable (i.e. they cannot be changed).

def replace_all_questions(input_string: str) -> str:
    solution = ''
    for idx, char in enumerate(input_string):
        if char != '?':
            solution += char
            continue

        letters = []
        if idx > 0:
            letters.append(input_string[idx - 1])
        if idx < len(input_string) - 1:
            letters.append(input_string[idx + 1])

        if 'a' not in letters:
            solution += 'a'
        elif 'b' not in letters:
            solution += 'b'
        else:
            solution += 'c'

    return solution
Enter fullscreen mode Exit fullscreen mode

Examples

$ ./ch-1.py a?z
"abz"

$ ./ch-1.py pe?k
"peak"

$ ./ch-1.py gra?te
"grabte"

$ ./ch-1.py gra?be
"gracbe"
Enter fullscreen mode Exit fullscreen mode

Task 2: Good String

Task

You are given a string made up of lower and upper case English letters only.

Write a script to return the good string of the given string. A string is called good string if it doesn’t have two adjacent same characters, one in upper case and other is lower case.

My solution

This is more straight forward, although GitHub Copilot got rather confused with what was expected. For this task, I start by setting the solution variable to the same as the input string.

I then have an loop that runs continuously. Within that is an inner loop with the variable idx which starts at zero until two less than the length of solution. This is done as we don't want to check the last character, it has no next character.

If the letter at that place is upper case and the next letter is the same but lower case, or visa versa, I remove those two characters, and the outer loop will be called again.

If no characters are removed, the else: break clause will exit the outer loop.

def good_string(input_string: str) -> str:
    solution = input_string
    while True:
        for idx in range(0, len(solution)-1):
            char = solution[idx]
            if ((char.isupper() and solution[idx + 1] == char.lower()) or
                    (char.islower() and solution[idx + 1] == char.upper())):
                solution = solution[:idx] + solution[idx + 2:]
                break
        else:
            break

    return solution
Enter fullscreen mode Exit fullscreen mode

The Perl solution follows the same logic, but with a slightly different syntax.

Examples

$ ./ch-2.py WeEeekly
"Weekly"

$ ./ch-2.py abBAdD
""

$ ./ch-2.py abc
"abc"
Enter fullscreen mode Exit fullscreen mode

Top comments (0)