How does this for loop and if statement work? - javascript

Trying to figure out in my own understanding how the for loop and if statement of this function work. This is so because having googled the challenge, this code is shorter but same result as my initial one. The confusion is at the longest variable. It stores the longest lengths of the words greater than str.length(5) - or I may be wrong. For some ununderstood reason, the length of language(8) is not stored in the variable although 5, 10 and 18 are.
function longestWord(str) {
str = str.split(" ");
var longest = 0;
var word = null;
for (var i = 0; i < str.length; i++) {
if (longest < str[i].length) {
console.log("str = " + str[i]);
longest = str[i].length;
console.log("longest = " + longest); //What happended to 8 for language?
word = str[i];
}
}
return word;
}
console.log(longestWord("Using the JavaScript language bademnostalgiastic"));

All this does it keep track of the longest word (and stores the char count in longest). For each iteration, it tests to see if the next string has more characters than the currently recorded longest string (determined by longest). If it does, it stores the new char count as it is the new "winner of being the longest".
Here's what's happening here:
take a string and split it up into words (determined by spaces)
at this point you have a string array of all the individual strings divided by " "
loop through all of the strings in the array
if the current string that you are iterating through has character counter more than any other previous ones, then store this current character count in the variable longest
continue the loop and use the above logic in the previous point
So at the end of this all you have the actual string (stored in word) and the character count (stored in longest) of the word with the most characters.

JavaScript is 10 characters long and is tested before language, so the if test fails and it is skipped.
It stores the longest lengths of the words greater than str.length(5)
No. It stores the longest length seen so far. It gets 5 when Using is tested, but that is quickly overwritten.

The length of "JavaScript" is 10, which is longer than "language". Since "JavaScript" comes first, "language" won't be longer than the longest, so the if statement will result in false.

array str[]={Using, the,JavaScript, language ,bademnostalgiastic}
Iteration 1
str[i]=Using
str.length=5 (a)
Longest =0 (b)
since (a)>(b)
Longest =5
word=Using
Iteration 2
str[i]=the
str.length=3 (a)
Longest =5 (b)
since (a)<(b)
Longest and word remain same
so,Longest =5
and,word=Using
Iteration 3
str[i]=JavaScript
str.length=10 (a)
Longest =5 (b)
since (a)>(b)
so,Longest =10
and,word=JavaScript
Iteration4
str[i]=language
str.length=8 (a)
Longest =10 (b)
since (a)<(b)
so longest remain same
so,Longest =10
and,word=JavaScript
Iteration5
str[i]=bademnostalgiastic
str.length=18 (a)
Longest =10 (b)
since (a)>(b)
so,Longest =18
and,word=bademnostalgiastic
END OF LOOP
so longest word bademnostalgiastic

Here's a breakdown:
str = str.split(" ");
This is making an array of strings split on spaces.
for (var i = 0; i < str.length; i++)
We're starting here with i (the iterator variable) at 0. We're going to keep doing this loop while i is less than the length of str. We're going to increase i by 1 each time we go through this loop.
if (longest < str[i].length)
Here we check if the longest we've saved is less than the string's length we're looking at.
longest = str[i].length;
Here we assign the new longest string, because this one is longer.
word = str[i];
We also save the word, likely so we can use it later.
return word;
After the loop ends, we're going to send word back as the result.
console.log(longestWord("Using the JavaScript language bademnostalgiastic"));
This is your call and print statement.
The reason you're seeing 5, 10, and 18, is because you're only printing out values when the value is bigger than what you've already seen.

Related

What is the purpose of dividing a string's length in a palindrome?

I am currently trying to understand what is achieved when we divide a string's length by two. I understand how the loop in the if statement works by comparing each character with the initial string, but I can't wrap my head around this part and I can't find a good explanation of it anywhere.
If we divide a string's length in two what is it doing? I.e. with the word 'Madam' - If 'i' is more than 5/2 [2.5], the loop stops incrementing? Once it has checked [m][0], [a][1], [d][2] - it stops at [a][3] because it is no longer necessary to check as we know it to already be true/false as it mirrors the other half of the word?
function aPalindrome(str) {
for (let i = 0; i < str.length / 2; i++) {
if (str[i] != str[str.length - 1 - i]) {
return false;
}
return true;
}
}
Palindrome is a word, phrase, or sequence that reads the same backwards as forwards. Therefore we divide it half to check with the other half. we don't need to check the whole thing.
With Example:
madam,
we are already checking str[0] == str[4],
therefore we don't need to check str[4] == str[0]

Understanding the .length property

Could someone please explain what the .length property is doing in the following code:
let sentenceCount = 0;
betterWords.forEach(word => {
if (word[word.length-1] === '.' || word[word.length-1] === '!') {
sentenceCount++;
}
});
I understand the basic idea of what .length does, but when I try to print out word[word.length], it prints out as undefined. If I print out word[word.length-1], then I get the . and ! in the text. I'm not understanding what word[word.length-1] actually is so that when -1 is attached it gets the characters on the end.
Thank you in advance for any advice on this.
JavaScript exhibits zero based indexing, that is, the first element in an array or in a string is at position 0. Therefore, an array or string of length n has elements going from position 0 to n - 1, with element at position n being undefined. This means that an array or string with n elements has the last element at n - 1, which is accessed as someArrayString[n - 1].
.length returns the length of an array or a string. Hence, the last element of an array or a string is found at someArrayString.length - 1 which is accessed as someArrayString[someArrayString.length - 1].
From the code, it can be inferred that word is a string. Therefore, the line word[word.length-1] accesses the last char (letter) in the word (although it actually accesses the last code unit
but in ASCII a code unit correspond with a 1 byte ASCII char).
For example, the string var word = "JavaScript" has length 10. With J at position 0 and t at position 9. In other words, word[0] == 'J' and word[word.length - 1] == 't'
Let's say your word = 'People';
word.length would return 6 which is the character number in your word.
Since arrays (in this case string because .length can be used in strings too) start from index 0, word.length-1 would give you the 5th element of your string, which is the last character of your word.
In your code, if (word[word.length-1] === '.' || word[word.length-1] === '!') checks if the last character of a word is a dot (.) or exclamation point (!) so you can count how many sentences there are in a given string.
word.length-1 - Returns the last index in the word
Explanation
word= 'test!';
console.log(word[word.length-1])
OUTPUT - !
The Length of word = 5
We need to get the last index of the word i.e word[4] as the array indexing starts from 0
Your .length property returns the length of the string. The string itself is a one-dimensional array with elements of the type character so using .length gives the size of the array. Arrays use zero-based indexing.
So in your case word[word.length-1] returns the last element/character of the array and word[word.length] goes beyond the bounds of the array and that's why it prints out undefined.
Here's a playground you can test it.
const string = "Just a test.";
//get the last element
console.log(string[string.length-1]);
//trying to get an element outside the bounds of the array
console.log(string[string.length]);
Alright, In your code I assume that betterWords is an array because you are using forEach.
And also assume the betterWords array is something like,
betterWords = ['word.','words!','hello','world'];
Length Property
The length property returns the length of array or string.
let myArray = [0,5,6,8,9];
let myString = 'hello';
console.log(myArray.length) // 5 | because myArray has total 5 elements.
console.log(myString .length) // 5 | because myString has total 5 characters.
Index
Then index tells us the position of an element in an array or a character in a string.
The index is starting from 0.
let myString = 'hello';
/*
* h e l l o
* - - - - -
* 0 1 2 3 4
*/
console.log(myString[0]); // h | because h is 0 index of hello
So now you can see the length of the word hello is 5. But the last index of the word hellois4`. Which means the last index = length - 1
That's why here we are subtracting 1 from length to get the last index.
console.log(word[word.length-1]);

Can someone explain what each variable, operator, argument etc in this loops work?

Just got into coding a week ago and I'm enjoying it for now. I realized I was going too fast through the curriculum on free code camp and will move onto the next section without fully understanding it. In this loop example, can someone explain to me how this loop fully works? The objective is to find the longest word in this sentence 'the quick brown fox jumped over the lazy dog.'
-What does the var i stand for in this case?
-I played around with changing 'i = 0' and put numbers 1-9 and checked the result and got:
numbers 0-4 gives me "6"
numbers 5-7 gives me "4"
numbers 8 gives me "3"
and 9 gives me 0
I don't understand how those numbers resulted in 6,4,3, and 0. Can someone explain this to me. Thanks!
function findLongestWordLength(str) {
var words = str.split(' ');
var maxLength = 0;
for (var i = 9; i < words.length; i++) {
if (words[i].length > maxLength) {
maxLength = words[i].length;
}
}
return maxLength;
}
console.log(findLongestWordLength("The quick brown fox jumped over the lazy dog"));
Indices start from #0 (the first word). #1 is the second word, etc. Word #8 of your sentence is "dog".
The i = 9 means start checking at word #9. (Which doesn't exist) and therefore results in the longest word has 0 letters.
If you start at word #5, you're only considering "over the lazy dog" and get the longest word has 4 letters.
If you start before that, you'll also consider "jumped" and you'll get the longest word has 6 letters.
Also: off topic pet peeve (sorry!): "The quick brown fox jumps over the lazy dog" is a pangram (contains every letter of the alphabet). But it is often misquoted as "jumped" instead of "jumps", which unfortunately makes it no longer a pangram because it needs the 's' from "jumps". :( So the answer should be 5. ;)
I have commented the code you posted with some explanations.
// This defines a function that takes a parameter which will be referred to as str inside this function
function findLongestWordLength(str) {
// this creates an array of strings by spliting the variable str on every space. Essentially this creates an array of the words in the input parameter
var words = str.split(' ');
// this is the value we will return to the user. We initialise it to 0 before going through the list of words. It will be used to hold the length of the longest word.
var maxLength = 0;
// this loops through the array of words we created earlier. var i is the loop variable/counter
// NOTE: this is setup wrong, var i should start from 0
// basically we're saying perform the code inside the for loop until i is higher than the number of words we have then stop.
// This is a traditional setup to loop through an array.
for (var i = 0; i < words.length; i++) {
// This if block is saying if the number of letters in the current word is more than the
// current maximum we have then it should be the new maximum
if (words[i].length > maxLength) {
maxLength = words[i].length;
}
}
// finally we return to the caller the maximum we found
return maxLength;
}
console.log(findLongestWordLength("The quick brown fox jumped over the lazy dog")); // 6 because jumped is the longest word
A little more explanation on for loops:
There are more than 1 way to loop through things. Loops are a way to perform the same code over and over again until a certain criteria is met.
Because we have a list of words and we know how many words we have a for loop is suitable to go through them.
A for loop setup in the way you have your code uses a counter.
First you set the initial value of the counter (0)
then you tell the loop the condition it needs to meet to stop looping, in this case when the counter reaches the number of words we have.
Finally, you specify a little bit of code to execute at the end of each iteration, in this case i++. i++ is essentially the same as i = i + 1 which increments the counter after each iteration. Without it we will never meet the criteria we set and the loop will execute forever.
I hope that helps.

Is the time complexity for this function O(N) or O(N^2)?

I am trying to determine the time complexity for the following function.
The function reverses the order of words in a string and then reverses the order of letters in a word.
For example:
“the sky is blue” => “eulb si yks eht”
var reverseString = function(s) {
let str = s.split(' ')
let word;
let wordRev;
let result = [];
let countI = 0
let countJ = 0
//lets call this loop "i"
for(let i=str.length-1; i>=0; i--) {
word = str[i]
wordRev = ""
countI +=1
//lets call this loop "j"
for(let j=word.length-1; j>=0; j--) {
wordRev += word[j]
countJ+=1
}
result.push(wordRev)
}
return result.join(" ")
};
Although there are two nested loops, I believe the time complexity is O(n) and I will give two scenarios as an example.
• Scenario 1:
⁃ s.length: 22
⁃ input: “thisisreallylongstring”
⁃ str: [“thisisreallylongstring”]
⁃ i loop count total: 1
⁃ j loop count total: 22
• Scenario 2
⁃ s.length = 11
⁃ input: “s t r i n g”
⁃ str: [“s”, “t”, “r”, “i”, “n”, “g”]
⁃ j loop count total: 6
⁃ i loop count total: 6
The count total of loops i and j are roughly equal to the length on the input, which leads me to believe that even though there are two nested loops it is still O(n) complexity.
Am i wrong in my line of thinking?
Two factors are at play here:
Your algorithm itself is O(n). The substrings processed in each inner loop are disjoint. That is, you have two nested loops, but the part of the string processed in the inner loop is never repeated by separate iterations in the outer loop. Each inner loop gets its own separate substring, and when you add them together, it's O(n).
Appending strings this way makes the algorithm O(n^2). Strings are immutable so each call to wordRev += word[j] will create a brand new string. In the worst case, such as for "thisisreallylongstring", you end up creating "g", "gn", "gni", ... as intermediate strings. Adding them together, it's O(n^2).
So the overall answer is O(n^2).
All you really care about is how many times the inner loop runs and if everything you are doing in the loops is constant time. In your case the inner loop always runs n times where n is the number of letters in your sentence. For testing you can make some fake sentences easily and actually count how many times the loop runs. So with a sentence made with: let str = Array.from({length: 20}, ()=>'a'.repeat(20)).join(' ') you'll find the inner loop runs exactly 400 times. Which is exactly how many letters you have. You sometimes need to be careful with the javascript functions because they don't always run in constant time — for example if you where splicing arrays in the loops, but you don't appear to be doing that here. Everything should run in linear time. So O(n) where n is the number of letters.

Sort all characters in a string

I'm trying to solve this problem where I want to sort array of characters in a string
Problem:
Sort an array of characters (ASCII only, not UTF8).
Input: A string of characters, like a full English sentence, delimited by a newline or NULL. Duplicates are okay.
eg: This is easy
Output: A string of characters, in sorted order of their ASCII values. You can overwrite the existing array.
eg: Taehiisssy
Solution Complexity: Aim for linear time and constant additional space.
I know that in JavaScript you can do something like
const sorted = str.split('').sort().join('')
EDIT: I'm trying to see if I can make use of charCodeAt(i) method if I can get anything out of it.
But this would be O(nLogN) ^^ not linear (+extra space O(N) for split)
But in constant space, how would we sort array of characters?
Character-by-character formulate a cumulative count
const s="This is easy";
// Create an array which will hold the counts of each character, from 0 to 255 (although strictly speaking ASCII is only up to 127)
let count = Array(256).fill(0);
// Look at each character in the input and increment the count for that character in the array.
for(let i=0; i<= s.length; i++) {
c=s.charCodeAt(i);
count[c]++;
}
let out="";
// Now scan through the character count array ...
for(let i=0; i<= 255; i++) {
// And for each character, e.g. "T", show it the number of times you saw it in the input
for(let rep=0; rep<count[i]; rep++){
out+=String.fromCharCode(i);
}
}
console.log(out);
This only uses a constant table size, 256 numbers long (or whatever number of different symbols you wish to allow).
And the time it takes is linearly dependent on the number of characters in the input string (assuming almost no time is spent on the inner FOR loop when the count is zero for that character).

Categories

Resources