Missing letters freecodecamp - javascript

Actually I found an answer a few minutes ago.
But I found something strange.
This is my answer for 'Missing letters' in freeCodeCamp challenges.
function fearNotLetter(str) {
var string;
for (i=0;i<str.length;i++) {
if(str.charCodeAt(i)+1 < str.charCodeAt(i+1)){
string = String.fromCharCode(str.charCodeAt(i)+1);
}
}
return string;
}
When I change < operator in if statement into != (not same), it doesn't work!
For me, it seems that != works exactly same as < operator does.
(Because 'not same' can mean something is bigger than the other.)
What is the difference between < and != in the code above?

Your code has a small defect that works when you use < but not !=.
If you see str.charCodeAt(i+1); this code is checking one spot past the end of the string on the last iteration and will return a NaN result.
If I provide the string "abce" it will check if f is < NaN. I believe NaN can't be compared to f's value so it doesn't go into the if statement. So it will keep the missing letter d that was found in the previous iterations which is stored in your string variable.
However, if you provide the !=, then with the same scenario it knows f != NaN and goes into the if statement. This then overwrite the actual missing letter and fails your FCC test case because it is replacing the missing d with f in your string variable.
To fix your code, simply change the for loop to end one iteration before the length of the string.
for (i = 0; i != str.length-1; i++) {
}

This is my method without using .charCodeAt() function :)
function fearNotLetter(str) {
var ind;
var final = [];
var alf =['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
str = str.split('');
ind = alf.splice(alf.indexOf(str[0]),alf.indexOf(str[str.length-1]));
for(var i=0;i<ind.length;i++){
if(str.indexOf(ind[i]) == -1){
final.push(ind[i]);
}
}
if(final.length != 0){
return final.join('');
}
return;
}
fearNotLetter("bcef");

My solution:
function fearNoLetter(str){
var j= str.charCodeAt(0);
for(var i=str.charCodeAt(0); i<str.charCodeAt(str.length-1); i++){
j = str.charCodeAt(i - str.charCodeAt(0));
if (i != j){
return String.fromCharCode(i);
}
}
}

My solution:
function fearNotLetter(str) {
let y = 0;
for (let i = str.charCodeAt(0); i < str.charCodeAt(str.length - 1); i++) {
if (str.charCodeAt(y) != i) {
return String.fromCharCode(i);
}
y++;
}
return;
}
console.log(fearNotLetter("ace"));

function fearNotLetter(str) {
let alpha = "abcdefghijklmnopqrstuvwxyz";
let alphabet = []
for(let j = 0; j< alpha.length; j++){
alphabet.push(alpha[j])
}
if (alphabet.length == str.length){
let result = undefined;
return result
}else{
const start =alphabet.indexOf(str[0])
let end = (str.length)-1
const stop = alphabet.indexOf(str[end])
const finish = alphabet.slice(start,stop)
let result = finish.filter(item => !finish.includes(item) || !str.includes(item))
result = String(result)
return result
}
return result
}
console.log(fearNotLetter("abcdefghijklmnopqrstuvwxyz"));

Related

The only word that is not passing the test is "almostomla."

I am learning JS on freecodecamp and am stuck on a problem. I am creating a palindrome checker. My code almost works. However, there is only one word that is not passing the test and that is almostomla. It is not a palindrome yet my code returns true. I have tried several things. Even rewrote the code and used the while loop but nothing seems to help. There is a solution at the freeCodecamp web but I have written the code in a different way and am unable to figure my mistake out.
Here is my code.
let reversedStr = [];
function palindrome(str) {
let d = str.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
for (let i = d.length - 1; i >= 0; i--) {
reversedStr.push(d[i]);
}
for (let j = 0; j < str.length; j++) {
if (reversedStr[j] == d[j]) {
return true;
} else {
return false;
}
}
}
console.log(palindrome("almostomla"));
This line if (reversedStr[j] == d[j]) {return true; returns as soon as the character matches at both the index. It does not check rest of the characters.
In fact you can just return as soon as the character in both index does not match.
Also note the reversedStr has to be inside the function. Else it will contain previous values
function palindrome(str) {
let reversedStr = [];
let d = str.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
for (let i = d.length - 1; i >= 0; i--) {
reversedStr.push(d[i]);
}
for (let j = 0; j < str.length; j++) {
if (reversedStr[j] !== d[j]) {
return false;
}
}
return true
}
console.log(palindrome("almostomla"));
console.log(palindrome("1221"));
Your code returns "true" or "false" after first match - it checks that 'a' is equal to 'a' and returns true.
You can return "false" from inside of cycle only if you found duplicated letter else return true after the cycle ends.

Codewars Javascript Problem- my code with a double for loop times out

I'm trying to solve a problem on Codewars which involves seeing if one string includes all the letters in a second string. I think I've found a decent solution, but my code times out (12000ms) and I can't figure out why. Could anyone shed some light on this issue?
function scramble(str1, str2) {
let i;
let j;
let x = str2.split();
for (i = 0; i < str1.length; i++) {
for (j = 0; j < str2.length; j++) {
if (str1[i] == str2[j]) {
x.splice(j, 1);
j--;
}
}
}
if (x.length == 0) {
return true;
} else {
return false;
}
}
If your strings have sizes N and M then your algorithm is O(N*M). You can get O(NlogN + MlogM) by sorting both strings and then do a simple comparison. But you can do even better and get O(N+M) by counting the letters in one string and then see if they are present in the other. E.g. something like this:
function scramble(str1, str2) {
let count = {}
for (const c of str1) {
if (!count[c])
count[c] = 1
else
count[c]++
}
for (const c of str2) {
if (!(c in count))
return false
count[c]--
}
for (let k in count) {
if (count.hasOwnProperty(k) && count[k] !== 0)
return false
}
return true
}
You created an infinite loop by both incrementing and decrementing j. The value of j gets stuck whenever str1[i] == str2[j]
Reducing your code snippet to the simplest form would look something like this:
for (j = 0; j < 10; j++) {
j--;
console.log(j) // always -1
}
You're adjusting x but then referring to str2 as if it has been changed. Because you never adjust str2, you're always comparing the same two letters, so you get stuck in a loop. That's one problem. Then, your question's wording suggests that we're checking if every letter in str2 is in str1, but you're going through every letter in str1 and checking it against str2. str1 should be the inner loop.
function scramble(str1, str2) {
var x = str2.split("");
for (var i = 0; i < x.length; i++) {
for (var j = 0; j < str1.length; j++) {
if (str1[j] == x[i]) {
x.splice(i--, 1);
}
}
}
return x.length === 0;
}
console.log(scramble("dirty rooms", "dormitory"));
console.log(scramble("cat", "dog"));
Because x.length === 0 is already a boolean value, you can just return that. No need for the if statements there. The triple equals checks the variable's type and value, and double equals only checks value. I tend to always use triple when I'm checking against 0 and 1 because you don't want unintended consequences like this:
console.log(false == 0, true == 1);
console.log(false === 0, true === 1);
Also, because i-- means "i = i - 1 after execution", you can put that directly in your call to splice, and it won't execute until after splice is finished. --i, on the other hand, would be evaluated before execution.
This is all great, but using indexOf is a simpler solution:
function scramble(str1, str2) {
for (let i = 0; i < str2.length; i++) {
if (str1.indexOf(str2[i]) == -1) return false;
}
return true;
}
console.log(scramble("forty five", "over fifty"));
console.log(scramble("cat", "dog"));

Trying to create a palindrome function that accounts for spaces

Okay so palindrome is a word that is the same spelled backwards. What if we want to take a phrase that is also the same backwards? So kook is one. race car is another one.
So I made one that doesn't account for spaces.
function isPal(string){
var l = string.length;
for (var i = 0; i < (l/2); ++i) {
if (string.charAt(i) != string.charAt(l - i - 1)){
return false;
}
}
return true;
}
This one works fine for words.
Now I'm thinking, push the string into an array, and split up each character into it's own string, then remove any spaces, and then run if (string.charAt(i) != string.charAt(string.length - i - 1)). So here's what I wrote but failed at..
function isPalindrome(string){
var arr = [];
arr.push(string.split(''));
for (i = 0; i < arr.length; i++){
if (arr[i] === ' '){
arr.splice(i, 1);
if I return arr, it still gives me the string with the space in it. How do I accomplish this? Thanks!
EDIT: Used the solution but still getting false on 'race car'
Here's what I got:
function isPalindrome(string){
var arr = string.split('');
for (i = 0; i < arr.length; i++){
if (arr[i] === ' '){
arr.splice(i, 1);
} else if (arr[i] != arr[arr.length - i - 1]){
return false;
}
}
return true;
}
where's my error?
Your problem is in the following line:
arr.push(string.split(''));
string.split('') returns an array. So, arr is actually an array with one entry it in (another array that contains your characters). Replace:
var arr = [];
arr.push(string.split(''));
with
var arr = string.split('');
and it should work as expected
Just check check the string without spaces:
function isPal(string){
string = string.split(" ").join(""); // remove all spaces
var l = string.length;
for (var i = 0; i < (l/2); ++i) {
if (string.charAt(i) != string.charAt(l - i - 1)){
return false;
}
}
return true;
}
isPal("a man a plan a canal panama"); // true
It seems much easier to just split into an array, reverse and join again to check if a word is a palindrome. If you want to ignore spaces, just remove all instances of spaces:
let word = 'race car';
let isPalindrome = (word) => {
let nospaces = word.replace(/\s/g, '');
return [...nospaces].reverse().join('') === nospaces;
}
Or non-es6:
var word = 'race car';
var isPalindrome = function(word) {
var nospaces = word.replace(/\s/g, '');
return nospaces.split('').reverse().join('') === nospaces;
}

String with the highest frequency of recurring letters in a word

This is a challenge for coderbyte I thought I'd try to do it using a different method for solving it than loops, objects. It passed but it isn't perfect. The directions for the challenge are:
Have the function LetterCountI(str) take the str parameter being passed and return the first word with the greatest number of repeated letters. For example: "Today, is the greatest day ever!" should return greatest because it has 2 e's (and 2 t's) and it comes before ever which also has 2 e's. If there are no words with repeating letters return -1. Words will be separated by spaces.
function LetterCountI(str){
var wordsAndLetters = {};
var count = 0;
var finalword;
str = str.split(" ");
for(var i = 0; i < str.length; i++){
wordsAndLetters[str[i]] = wordsAndLetters[str[i]] || 0;
}
function countWordLetters(strs){
strs = strs.split("");
var lettercount = {};
for(var i = 0; i <strs.length; i++){
lettercount[strs[i]] = lettercount[strs[i]] || 0;
lettercount[strs[i]]++;
}
return lettercount;
}
for(var words in wordsAndLetters){
wordsAndLetters[words] = countWordLetters(words);
var highestLetterFrequency = wordsAndLetters[words];
for(var values in highestLetterFrequency){
if(highestLetterFrequency[values] > count){
count = highestLetterFrequency[values];
finalword = words;
}
if(count !== 1){
return finalword;
}
}
}
return -1;
}
LetterCountI("today is the greatest day ever!");
Sorry if some of the variable names are confusing I've been up for far too long trying to figure out what I did wrong. If you use the parameters at the bottom of the code it returns 'greatest' like it should however change the parameters to
LetterCountI("toddday is the greatttttest day ever!");
and it logs 'toddday' when it should log 'greatttttest'. Is my code completely wrong? I realize if the parameters were ("caatt dooog") it should log 'caatt' since there are 4 recurring letters but I'm not worried about that I just am concerned about it finding the most recurrence of one letter(but by all means if you have a solution I would like to hear it!). Any changes to the variables if needed to make this code more readable would be appreciated!
The problem with your code is the positioning of the following section of code:
if(count !== 1){
return finalword;
}
Move it from where it currently is to just before the return -1, like so:
for(var words in wordsAndLetters){
wordsAndLetters[words] = countWordLetters(words);
var highestLetterFrequency = wordsAndLetters[words];
for(var values in highestLetterFrequency){
if(highestLetterFrequency[values] > count){
count = highestLetterFrequency[values];
finalword = words;
}
}
}
if(count !== 1){
return finalword;
}
return -1;
The problem with your original code is that your were returning the first word that had repeating characters, which meant your code didn't get far enough to check if any subsequent words had more repeating characters.
Also, just for fun, here is my alternative solution.
Here you go
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
function LetterCountI(str){
var temp = str.split(" ");
var final = '', weight = 0;
for(var i = 0; i < temp.length; ++i) {
var word = temp[i].split("");
if(word.getUnique().length < word.length) {
var diff = word.length - word.getUnique().length;
if(diff > weight){
weight = diff;
final = temp[i];
}
}
}
return final;
}
console.log(LetterCountI("Catt dooog"));
console.log(LetterCountI("toddday is the greatttttest day ever!"));
Viva LinQ !!!!!
var resultPerWord = new Dictionary<string, int>();
var S = "toddday is the greatttttest day ever!";
foreach(var s in S.Split(' '))
{
var theArray =
from w in s
group w by w into g
orderby g.Count() descending
select new { Letter = g.Key, Occurrence = g.Count() };
resultPerWord.Add(s, theArray.First().Occurrence);
}
var r = "-1";
if (resultPerWord.Any(x => x.Value >1))
{
r = resultPerWord.OrderByDescending(x => x.Value).First().Key;
}

Array of digit as string to simple int conversion problem

Console debug shows me that array is ex. ["2"], but I need [2].
Why casting doesnt'work?
function filterElements(deals) {
var result = deals,
categories= $('#deals-categories').data('current_category');
if (categories != undefined && categories.length > 0) {
for (var i; i < categories.length; i++) {
categories[i] = parseInt(categories[i]);
}
console.log(categories, 'cats');
result = $.grep(result, function(e) {
return $.inArray(e.category_id, categories) != -1;
});
}
return result;
}
You need to initialize var i = 0 in the loop declaration.
Full code cleanup:
function filterElements(deals) {
var result = deals,
categories = $('#deals-categories').data('current_category');
if (categories && categories.length) {
for (var i=0; i<categories.length; i++) {
categories[i] = parseInt(categories[i], 10);
}
console.log(categories, 'cats');
result = $.grep(result, function(e) {
return $.inArray(e.category_id, categories) !== -1;
});
}
return result;
}
use categories[i] * 1 to cast
parseInt works in a bit unexpected way sometimes :)
parseInt("010") will return 8 in some browsers, and 10 in others: http://www.w3schools.com/jsref/jsref_parseInt.asp
Are you sure? This is an example similar to yours:
var strings = ["1", "2", "3"];
var valueAsInt = 0;
for(var i = 0; i < strings.length; i++){
valueAsInt = parseInt(strings[i]);
if(typeof(valueAsInt) == 'number'){
alert('Is an integer');
}
}
The message 'Is an integer' is shown three times. I think in your code the parser works, but maybe later, the value is converted to string by comparing with other string or, maybe some concatenation.

Categories