Coding/Blog challenge 13

Coding/Blog challenge 13

It's a fine day here in the beautiful Ozark Mountains, what a day to do some coding problems. Actually, this practice will hopefully pay off as I have a technical interview scheduled for later today. It's probably a whiteboarding problem as well. Anyway, lets hop into it.

Challenger

This one is from CodeWars again, & I found it to be interesting. It required a bit of thought and pseudo-code to step my way through the process.

Description: Write a function named first_non_repeating_letter that takes a string input, and returns the first character that is not repeated anywhere in the string.

For example, if given the input 'stress', the function should return 't', since the letter t only occurs once in the string, and occurs first in the string.

As an added challenge, upper- and lowercase letters are considered the same character, but the function should return the correct case for the initial letter. For example, the input 'sTreSS' should return 'T'.

If a string contains all repeating characters, it should return an empty string ("") or None -- see sample tests.

My thoughts & process

My first line of thinking was going to use a similar algorithm as I used last blog to count characters of a string. But I decided on a different line of thought after a few seconds. There are many ways to solve this, as always.

First, we need to set up our function. After setting up our function, we want to set up a loop to go over each character of the arguments string.

//start the function
function firstNonRepeatingLetter(s) {
    //loop over all of argument
    for (let i = 0; i < s.length; i++) {

    }
    return 
}

The next step I chose to do was, as I loop over the string, remove the current letter and see if the current letter is still in the string. If the string does NOT include our current letter, return the current letter. If the string still contains our current letter, we keep looping till we find a non-repeating letter or reach the end of the argument's string. Here is an example of what I mean using the word "newness"

// here's psuedo-code
for(loop over string){
    log each version of word with current index value removed
}
//1st iteration outputs: "ewness" (Does this string still have "n")
//2nd iteration outputs: "nwness" (Does this string still have "e")
//3rd iteration outputs: "neness"(Does this string still have "w")
    //word does not include "w" any longer so we return current letter

I chose to initialize a variable & use the String object's slice method. I slice at the first letter through our current letter. Then I will concatenate, starting at the letter after our current letter through the remaining letters.

function firstNonRepeatingLetter(s) {
    //we loop through the arguments string
    for (let i = 0; i < s.length; i++) {
        //set variable that slices current letter out of a string
        let trimALetter = (s.slice(0, i) + s.slice(i + 1, s.length));
    }
    return;
}

The next piece of logic is, if this new string doesn't contain the letter we removed, return this letter. If it does still contain the letter, we know it's a repeated letter and the loop continues.

function firstNonRepeatingLetter(s) {

    for (let i = 0; i < s.length; i++) {
        let trimALetter = s.slice(0, i) + s.slice(i + 1, s.length));
        //check to see if new word contains a duplicate
        if (! (trimALetter.includes(s[i]))) {
            //return the letter that first meets this criteria
            return s[i];
        }
    }
    return;
}

We're almost done, the problem also states that we need to account for case sensitivity. Even if a letter is capitalized, it can be duplicated in lowercase. Example: the word "Newness" still has two n's, even if its first appearance is capitalized. I used the toLowerCase method to account for this. The problem also states that if the argument doesn't have any single appearance letters, it will return an empty string. So if the loop runs through arguments characters and there are only duplicates, we return the empty string.

function firstNonRepeatingLetter(s) {

    for (let i = 0; i < s.length; i++) {
        //convert new string to lowercase
        let trimALetter = (s.slice(0, i) + s.slice(i + 1, s.length)).toLowerCase();
        //lowercase the current letter
        if (!(trimALetter.includes(s[i].toLowerCase()))) {
            return s[i];
        }
    }
    //return the empty string if only duplicates make up the argument
    return "";
}

In hindsight, it might be better to initialize a new variable to have the same value as the argument, but all lowercase. This way you are using fewer methods, but this was my first solution. That's the beauty of code, though, it can always be refactored.

Thanks for reading!