freeCodeCamp Challenge Guide: Missing letters

freeCodeCamp Challenge Guide: Missing letters
0

Missing Letters


Problem Explanation

You will create a program that will find the missing letter from a string and return it. If there is no missing letter, the program should return undefined. There is currently no test case for the string missing more than one letter, but if there was one, recursion would be used. Also, the letters are always provided in order so there is no need to sort them.

Relevant Links


Hints

Hint 1

You will need to convert from character to ASCII code using the two methods provided in the description.

Hint 2

You will have to check for the difference in ASCII code as they are in order. Using a chart would be very helpful.

Hint 3

You will need to figure out where the missing letter is, along with handling the case that there is not missing letter as it needs an specific return value.


Solutions

Solution 1 (Click to Show/Hide)
function fearNotLetter(str) {
  for (var i = 0; i < str.length; i++) {
    /* code of current character */
    var code = str.charCodeAt(i);

    /* if code of current character is not equal to first character + no of iteration
        hence character has been escaped */
    if (code !== str.charCodeAt(0) + i) {
      /* if current character has escaped one character find previous char and return */
      return String.fromCharCode(code - 1);
    }
  }
  return undefined;
}

// test here
fearNotLetter("abce");

Code Explanation

  • This solutions makes use of a for loop.
  • Code of encountered character is stored in code.
  • It is checked if code of current character is the expected one (no characters are skipped) by using the logic - code of current character = code of first character + number of iterations.
  • If a character is missing, the missing character is found and the final string is returned.
  • undefined is returned if there is no missing character in the string.

Relevant Links

Solution 2 (Click to Show/Hide)
// Adding this solution for the sake of avoiding using 'for' and 'while' loops.
// See the explanation for reference as to why. It's worth the effort.

function fearNotLetter(str) {
  var compare = str.charCodeAt(0),
    missing;

  str.split("").map(function(letter, index) {
    if (str.charCodeAt(index) == compare) {
      ++compare;
    } else {
      missing = String.fromCharCode(compare);
    }
  });

  return missing;
}

// test here
fearNotLetter("abce");

Code Explanation

  • First we define variables to store the character code for the first letter in the string, and to store whatever missing letters we may find.
  • We turn the string to an array in order to map through it instead of using for and while loops.
  • As we map through our letters’ character codes, we go comparing with the one that should be in that position.
  • If the current letter matches, we move the comparison variable to its next position so we can compare on the next cycle.
  • If not, the missing letter will be assigned to the missing variable, which will be returned after the map is finished.
  • If there are no missing characters, return undefined.

Relevant Links

Solution 3 (Click to Show/Hide)
function fearNotLetter(str) {
  for (let i = 1; i < str.length; ++i) {
    if (str.charCodeAt(i) - str.charCodeAt(i - 1) > 1) {
      return String.fromCharCode(str.charCodeAt(i - 1) + 1);
    }
  }
}

Code Explanation

  • Loop over the string
  • Check if the difference in char codes between adjacent characters in the string is more than 1 (check ASCII table)
  • Return the missing character ( +1 from where the gap was detected)
function fearNotLetter(str) {
  var allChars = "";
  var notChars = new RegExp("[^" + str + "]", "g");

  for (var i = 0; allChars[allChars.length - 1] !== str[str.length - 1]; i++)
    allChars += String.fromCharCode(str[0].charCodeAt(0) + i);

  return allChars.match(notChars)
    ? allChars.match(notChars).join("")
    : undefined;
}

// test here
fearNotLetter("abce");

Code Explanation

  • A new string allChars is created.
  • Create a regular expression notChars which selects everything except str.
  • The for loop is used to add all the letters in the range to allChars.
  • match() is used to strip off the str letters from the newly created string and it is returned.
  • If there are no missing characters, return undefined.

Relevant Links

5 Likes

I’ve got the feeling that more often than not, the basic solution is more straightforward and much more readable. Sometimes, it feels like the more advanced solutions are akin to killing a fly using a bazooka! I used to feel bad having my solution look more basic than advanced, but I think that simplicity and readability on projects at scale can be much more beneficial than using higher-end functions and techniques.
What’s your take on this?

35 Likes

Thank you @P1xt for the thoughtful and useful answer (as I’ve already come of expect of you). You’re a very generous contributor to this forum, thank you!

So what advice would you give to reach the right balance between simplicity, readability and efficiency, and in particular in regard to FCC’s challenges? I want to make sure I learn in a way that would be most useful for me in the future.

I also have a quick question concerning the benchmarks. What’s the fastest way to run them? Do you use benchmark.js with node.js installed on your own computer? Is there an easy way to run these benchmarks online?

Here is my super lazy algorithm, sans UTF-16 or regex. I think I need to go to bed as I completely missed the charCodeAt() hint LOL.

function fearNotLetter(str) {
  var alphabet = 'abcdefghijklmnopqrstuvwxyz';
  var len = str.length;
  var start = alphabet.indexOf(str[0]);
  
  for(var i = start; i < start + len; i++){
    if(!str.includes(alphabet[i])){
      return alphabet[i];
    }
  }
  return undefined;
}
18 Likes
function fearNotLetter(str) {
  var codePoints = str.split("").map(function(char, index) {
    return str.charCodeAt(index);
  });
  
  for (var i = 1; i < codePoints.length; i++) {
    if (codePoints[i-1] !== codePoints[i]-1) {
      return String.fromCharCode(codePoints[i]-1);
    }
  }

  return undefined;
}

I really like this solution.

1 Like

Thoughts on this solution?

function fearNotLetter(str) {
  var missing;
  
  for(var i = 1; i < str.length; i++) {
    if(str.charCodeAt(i) !== str.charCodeAt(i - 1) + 1) {
      missing = String.fromCharCode(str.charCodeAt(i - 1) + 1);
    }
  }
  return missing;
}
3 Likes

This is my piece of code. Easily understandable without any difficulties.

Code:

function fearNotLetter(str) {
  var alph = "abcdefghijklmnopqrstuvwxyz";
  
  if(alph.includes(str))
    return undefined;
  else {
    
        var i = 0;
    
      while (i<alph.length){

        if(alph.charCodeAt(i) !== str.charCodeAt(i))
          return String.fromCharCode(alph.charCodeAt(i));
        i++; 
        
      }
  }
}

fearNotLetter("abce");

What is your take on this guys?

My solution to this challenge:

function fearNotLetter(str) {
  for (var i = str.charCodeAt(0); i < str.charCodeAt(str.length - 1); i++) {
    if (str.indexOf(String.fromCharCode(i)) == -1) {return String.fromCharCode(i);}
  }
}

fearNotLetter("abce");

Is it really bad? And if it is - please explain why?
(Sorry for my bad English)

5 Likes

My solution:

function fearNotLetter(str) {
  var missing;
  var first = str.charCodeAt(0);
  var last = str.charCodeAt(str.length - 1);
  for(var i = first; i < last; i++){
    if(str.indexOf(String.fromCharCode(i)) < 0){
      missing = String.fromCharCode(i);
    }
  }
  return missing;
}
1 Like

Use the reduce method

function fearNotLetter(str) {
  var lost;
  str = str.split('');
  str.reduce(function(acc, val){
    if (val.charCodeAt() - acc.charCodeAt() != 1) 
      lost = String.fromCharCode(val.charCodeAt() - 1);
    return val;
  }, String.fromCharCode(str[0].charCodeAt() - 1));
  return lost;
}

fearNotLetter("de");

I have a few questions regarding this code.

  • allChars[allChars.length-1] !== str[str.length-1] until the last chars are equal, I get it. I think however that the syntax of a While loop will easier to understand and more suitable.

  • Can u explain new RegExp('[^'+str+']','g'); ? From my understanding `[^str]’ means searching out of the parentheses. Why is it necessary, there is no paretheses, so why do we need to mention it?

yeah, following the more advanced examples are great practice, but I hate to use code until after I understand it well enough to explain it in my comments…

Hi guys check out my implementation of the Missing letters algorithm.

function fearNotLetter(str) {
  var startStrCharCode = str.charCodeAt(0);
  var endStrCharCode = str.charCodeAt(str.length - 1);
  var sumOfCompleteCharCode = 
      (((endStrCharCode + 1) - startStrCharCode) * (endStrCharCode + startStrCharCode))/2;

  var actualCount = str.split('').reduce(function(acc, value){
    acc += value.charCodeAt(0);
    return acc;
  }, 0);

  var missingChar = sumOfCompleteCharCode - actualCount;
  if(missingChar === 0){
    return undefined;
  }
  return String.fromCharCode(missingChar);

}

It uses the sum of the first n integer algorithm SUM(N) = n(n+1)/2. if n does not start from 1 the but starts from r and ends at n formula becomes
SUM(of integers starting from r to n) = [(n + 1) - r]( n + r ) / 2


function fearNotLetter(str) {
  var min = Math.min(str.charCodeAt(0), str.charCodeAt(str.length-1));
  var max = Math.max(str.charCodeAt(0), str.charCodeAt(str.length-1));
  var codeArr = [];
  for(var i = min; i <= max; i++) {
    codeArr.push(String.fromCharCode(i));
  }
  for (var j=0; j<codeArr.length; j++) {
    if (str.indexOf(codeArr[j]) === -1) {
      return codeArr[j];
    }
  }
}
1 Like

I feel like my code should work but it doesn’t! Check it out and let me know why it’s incorrect. Thanks

//

function fearNotLetter(str) {
var abc = ‘abcdefghijklmnopqrstuvwxyz’;
var answer ;
var arr = abc.substr(str[0], str.length +1);

var i;

for (i=0; i<arr.length; i++) {

if (str.indexOf(arr[i]) == -1)
  {
    return arr[i];
  }

}
return undefined;
}

fearNotLetter(“abce”);

//

This is my solution:

function fearNotLetter(str) {

  var strArr = str.split("");
  
  for(var i=0; i<strArr.length; i++){
    var code = str.charCodeAt(i);
    if( code !== str.charCodeAt(0) + i){
      return String.fromCharCode(code -1);
    }
    
  }
  return undefined;
}

//test
fearNotLetter("abd");

Here is mine, …

function fearNotLetter(str) {
  var ar = [];
  var p = "";
  
  for (var e in str){
    ar.push(str.charCodeAt(e));
  }
  
  for (var x=0; x<ar.length-1; x++){
    if (ar[x]+1 !== ar[x+1]){
      p = ar[x]+1;
      return String.fromCharCode(p);
    }
  }
  
return undefined;
}