Creating an Iterative - Javascipt - javascript

I have a recursive function below and I was just wondering how can I create an iterative (i.e. loops without recursion) for the same thing. I would really appreciate any help or suggestions thank you!
function countPalindromes(string, count) {
if (string.length <= 1) {
return count;
}
let [ firstLetter ] = string;
let lastLetter = string[string.length - 1];
if (firstLetter === lastLetter) {
let stringWithoutFirstAndLastLetters = string.substring(1, string.length - 1);
return countPalindromes(stringWithoutFirstAndLastLetters, count + 1);
} else {
return count;
}
}
console.log(countPalindromes("level", 0));
console.log(countPalindromes("aya", 0));

Took me a while, but this should work.
function countPalindromes(string, count) {
for (i = 0; i < Math.floor(string.length/2); i++) {
if (string.charAt(i) === string.charAt(string.length - i-1)) {count++};
}
return count;
}
console.log(countPalindromes("level", 0));
console.log(countPalindromes("aya", 0));

You can do something like this:
function countPalindromes(string) {
let count = 0;
for (let i = 0; i < Math.floor(string.length / 2); i++) {
const letterFromTheStart = string[i];
const letterFromTheEnd = string[(string.length - 1) - i];
if (letterFromTheStart !== letterFromTheEnd) {
break;
}
count++;
}
return count;
}
console.log(countPalindromes("level"));
console.log(countPalindromes("aya"));
The important parts are i < Math.floor(string.length / 2) and (string.length - 1) - i.
The first one assures the loop stops before or at the half of the string and the second gets the nth character starting from the string's end.

I didn't get your recursive palindrome function. Just converted the recursive one to iterative one.
function countPalindromes(string, count) {
if (string.length <= 1) {
return count;
}
let i = 0, j = string.length-1;
for (; i < j && string[i] == string[j]; i++, j--);
return i;
}
console.log(countPalindromes("level", 0));
console.log(countPalindromes("aya", 0));

You can reverse the string and compare letters until you hit a mismatch returning the last index that matched plus one.
function isPalindrome(word) {
const drow = word.split('').reverse();
for (i = 0; i < drow.length && drow[i] === word[i]; i++);
return i;
}
console.log(isPalindrome("level"));

Related

Sum All Primes Below a Given Number | Intermediate Javascript Algorithm | Recursion

Question
A prime number is a whole number greater than 1 with exactly two divisors: 1 and itself. For example, 2 is a prime number because it is only divisible by 1 and 2. In contrast, 4 is not prime since it is divisible by 1, 2 and 4.
Rewrite sumPrimes so it returns the sum of all prime numbers that are less than or equal to num.
My Attempt
const isPrime = a => {
for(let i = 2; i < a; i++)
if(num % i === 0) return false;
return a > 1;
}
function sumPrimes(num, total = []) {
let numVar = num;
let n = total.reduce((aggregate, item)=>{
return aggregate + item;
}, 0);
if(n > numVar){
return n;
}
for(let i = 1; i <= numVar; i++){
if(isPrime(i)== true){
total.push(i);
}
}
return sumPrimes(num, total);
}
sumPrimes(10);
The Problem
It says: 'Num is not defined'
I am not sure if there are other errors.
My Question
Please could you help me find the error, and fix the code to solve the algorithm?
This was a simple syntax error identified by #Jonas Wilms (upvote him in the comment above :))!
By replacing the 'a' with 'num' the function was fixed.
const isPrime = a => {
for(let i = 2; i < a; i++)
if(a % i === 0) return false;
return a > 1;
}
function sumPrimes(num, total = []) {
let numVar = num;
let n = total.reduce((aggregate, item)=>{
return aggregate + item;
}, 0);
if(n > numVar){
return n;
}
for(let i = 1; i <= numVar; i++){
if(isPrime(i)== true){
total.push(i);
}
}
return sumPrimes(num, total);
}
console.log(sumPrimes(10));
this simple function may help you,
function isPrime(num) {
for (var i = 2; i < num; i++)
if (num % i === 0) return false;
return num > 1;
}
function sumPrimes(num) {
let tot = 0;
for (let i = 0; i < num; i++)
if (isPrime(i))
tot += i;
return tot;
}
console.log(sumPrimes(10));

Repeat String Infinitely - Return Count of Specific Character Within N Length of Infinite String - JavaScript

Trying to solve this HackerRank challenge:
Lilah has a string, s, of lowercase English letters that she repeated infinitely many times.
Given an integer, n, find and print the number of letter a's in the first letters of Lilah's infinite string.
For example, if the string s = abcac and n = 10, the substring we consider is abcacabcac, the first 10 characters of her infinite string. There are 4 occurrences of "a" in the substring.
I wrote:
function repeatedString(s, n) {
s = s.repeat(n);
s = s.slice(0, n);
let array = Array.from(s);
let count = 0;
for (let i = 0; i < array.length; i++) {
let char = array[i];
if (char.match(/[a]/gi)) {
count++;
}
}
return count;
}
console.log(repeatedString("abcac", 10));
But HackerRank does not like s = s.repeat(n);, apparently:
I'm not sure how else to generate a string of an appropriate length to slice from. s = s.repeat(Infinity) does not work, and s is not already repeated an infinite number of times when it's passed in as a parameter.
I.e. console.logging(s), initially, logs
abcac
In this case.
I also tried:
function repeatedString(s, n) {
let j = n;
let newString = "";
while (n > 0) {
newString += s;
n--;
}
newString = newString.slice(0, j);
let count = 0;
let array = Array.from(newString);
for (let i = 0; i < array.length; i++) {
let char = array[i];
if (char.match(/[a]/gi)) {
count++;
}
}
return count;
}
console.log(repeatedString("abcac", 10));
But this caused a timeout error.
Any other ideas for how to create a string of valid length to slice from?
EDIT:
Constraints:
1 <= |s| <= 100
1 <= n <= 10^12
For 25% of the test cases, n <= 10^6
actually repeating the string n times is a tremendous waste of memory and runtime.
just compute how often the entire string would be repeated times how many as the string has plus the number of as in the part of s.slice(0, n%s.length)
And your runtime goes down to s.length instead of n
function repeatedString(s, n) {
var r = n % s.length,
m = (n - r) / s.length,
count = 0;
for (var i = 0; i < s.length; ++i) {
if (s[i] === "a") {
count += m + (i < r);
}
}
return count;
}
console.log(repeatedString("abcac", 1234567890));
function repeatedString(s, n) {
var r = n % s.length,
m = (n - r) / s.length,
count = 0;
for (var i = 0; i < s.length; ++i) {
if (s[i] === "a") {
count += m + (i < r);
}
}
return count;
}
console.log(repeatedString("abcac", 1234567890));
I tested this and knows it works. Essentially, I'm not creating a new string, I just find out how many times I have to multiply the original string in order to be able to truncate it. Then I multiply that number by how many a's there were in the original string.
function repeatedString(s, n) {
var charLength = s.length;
var repeat = Math.floor(n/charLength);
var remainder = n%(charLength);
var strCut = s.slice(0, remainder);
let count = 0;
let arrayX = Array.from(s);
for (let i = 0; i < arrayX.length; i++) {
let char = arrayX[i];
if (char.match(/[a]/gi)) {
count++;
}
}
count = count * repeat;
let arrayY = Array.from(strCut);
for (let i = 0; i < arrayY.length; i++) {
let char = arrayY[i];
if (char.match(/[a]/gi)) {
count++;
}
}
return count;
}
console.log(repeatedString("abcac", 10));
I tried a small solution with .repeat but as Thomas said, it's expensive and was taking ages to run tests.
function repeatedString(s, n) {
const allAs = s.match(/a/g);
if (!allAs) {
return 0;
}
if (s === 'a') {
return n;
}
const reps = s.repeat(Math.ceil(n/s.length)).slice(0, n).match(/a/g)
if (!reps) return 0;
return reps.length;
};
console.log(repeatedString('abc', 10));
console.log(repeatedString('abcde', 10));
But I followed Thomas idea and came up with a simpler solution
function repeatedString(s, n) {
const allAs = s.match(/a/g);
if (!allAs) {
return 0;
}
if (s === 'a') {
return n;
}
const rem = n % s.length;
const reps = (n-rem)/s.length;
let count = reps * allAs.length;
if (rem) {
const rest = s.slice(0, rem).match(/a/g);
if (rest) count = count + rest.length
}
return count;
}
console.log(repeatedString('a', 100000));
console.log(repeatedString('abcde', 10000000000));
You could use while loop to repeat original string until length is matched and then match to count the numbers of a.
function repeatedString(s, n) {
let i = 0, l = s.length;
while (s.length < n) s += s[i++ % l]
return s.match(/a/g).length;
}
console.log(repeatedString("abcac", 10));
I did this code and it worked well.
function repeatedString(s, n) {
let modulus = n % s.length;
let repetition = (n - modulus) / s.length;
let remainCounts = s.slice(0, modulus).split("").filter((item) => item == "a").length
return (s.split("").filter((item) => item == "a").length * repetition) + remainCounts
}
enter image description here

Happy numbers - recursion

I have an issue with a recursive algorithm, that solves the problem of finding the happy numbers.
Here is the code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return false;
}
}
}
}
CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Algorithm is working ALMOST fine. I've tested it out by calling function with different numbers, and console was displaying correct results. The problem is that I almost can't get any value from the function. There are only few cases in which I can get any value: If the number is build out of ,,0", and ,,1", for example 1000.
Because of that, I figured out, that I have problem with returning any value when the function is calling itself again.
Now I ended up with 2 results:
Returning the
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
which is giving an infinity looped number. For example when the number is happy, the function is printing in the console number one again and again...
Returning the
//return true
or
//return false
which gives me an undefined value
I'm a little bit in check by this problem, and I'm begging you guys for help.
I would take a step back and reexamine your problem with recursion in mind. The first thing you should think about with recursion is your edge cases — when can you just return a value without recursing. For happy numbers, that's the easy case where the sum of squares === 1 and the harder case where there's a cycle. So test for those and return appropriately. Only after that do you need to recurse. It can then be pretty simple:
function sumSq(num) {
/* simple helper for sums of squares */
return num.toString().split('').reduce((a, c) => c * c + a, 0)
}
function isHappy(n, seen = []) {
/* seen array keeps track of previous values so we can detect cycle */
let ss = sumSq(n)
// two edge cases -- just return
if (ss === 1) return true
if (seen.includes(ss)) return false
// not an edge case, save the value to seen, and recurse.
seen.push(ss)
return isHappy(ss, seen)
}
console.log(isHappy(23))
console.log(isHappy(22))
console.log(isHappy(7839))
Here's a simplified approach to the problem
const digits = x =>
x < 10
? [ x ]
: [ ...digits (x / 10 >> 0), x % 10 ]
const sumSquares = xs =>
xs.reduce ((acc, x) => acc + x * x, 0)
const isHappy = (x, seen = new Set) =>
x === 1
? true
: seen.has (x)
? false
: isHappy ( sumSquares (digits (x))
, seen.add (x)
)
for (let n = 1; n < 100; n = n + 1)
if (isHappy (n))
console.log ("happy", n)
// happy 1
// happy 7
// happy 10
// ...
// happy 97
The program above could be improved by using a technique called memoization
Your code is almost correct. You just forgot to return the result of the recursive call:
function TestingFunction(number){
sumNumberContainer = new Array(0);
if (CheckIfNumberIsHappy(number))
console.log(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
for (let i=0; i<100; ++i)
TestingFunction(i.toString()); // 1 7 10 13 ... 91 94 97
I've got the solution, which was given to me in the comments, by the user: Mark_M.
I just had to use my previous
return true / return false
also I had to return the recursive statement in the function, and return the value of the CheckIfTheNumberIsHappy function, which was called in TestingFunction.
The working code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
return CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Thanks for the great support :)

How do you iterate over an array every x spots and replace with letter?

/Write a function called weave that accepts an input string and number. The function should return the string with every xth character replaced with an 'x'./
function weave(word,numSkip) {
let myString = word.split("");
numSkip -= 1;
for(let i = 0; i < myString.length; i++)
{
numSkip += numSkip;
myString[numSkip] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
I keep getting an infinite loop. I believe the answer I am looking for is "wxaxe".
Here's another solution, incrementing the for loop by the numToSkip parameter.
function weave(word, numToSkip) {
let letters = word.split("");
for (let i=numToSkip - 1; i < letters.length; i = i + numToSkip) {
letters[i] = "x"
}
return letters.join("");
}
Well you need to test each loop to check if it's a skip or not. Something as simple as the following will do:
function weave(word,numSkip) {
var arr = word.split("");
for(var i = 0; i < arr.length; i++)
{
if((i+1) % numSkip == 0) {
arr[i] = "x";
}
}
return arr.join("");
}
Here is a working example
Alternatively, you could use the map function:
function weave(word, numSkip) {
var arr = word.split("");
arr = arr.map(function(letter, index) {
return (index + 1) % numSkip ? letter : 'x';
});
return arr.join("");
}
Here is a working example
Here is a more re-usable function that allows specifying the character used for substitution:
function weave(input, skip, substitute) {
return input.split("").map(function(letter, index) {
return (index + 1) % skip ? letter : substitute;
}).join("");
}
Called like:
var result = weave('weave', 2, 'x');
Here is a working example
You dont need an array, string concatenation will do it, as well as the modulo operator:
function weave(str,x){
var result = "";
for(var i = 0; i < str.length; i++){
result += (i && (i+1)%x === 0)?"x":str[i];
}
return result;
}
With arrays:
const weave = (str,x) => str.split("").map((c,i)=>(i&&!((i+1)%x))?"x":c).join("");
You're getting your word greater in your loop every time, so your loop is infinite.
Try something like this :
for(let k = 1; k <= myString.length; k++)
{
if(k % numSkip == 0){
myString[k-1]='x';
}
}
Looking at what you have, I believe the reason you are getting an error is because the way you update numSkip, it eventually becomes larger than
myString.length. In my code snippet, I make i increment by numSkip which prevents the loop from ever executing when i is greater than myString.length. Please feel free to ask questions, and I will do my best to clarify!
JSFiddle of my solution (view the developer console to see the output.
function weave(word,numSkip) {
let myString = word.split("");
for(let i = numSkip - 1; i < myString.length; i += numSkip)
{
myString[i] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
Strings are immutable, you need a new string for the result and concat the actual character or the replacement.
function weave(word, numSkip) {
var i, result = '';
for (i = 0; i < word.length; i++) {
result += (i + 1) % numSkip ? word[i] : 'x';
}
return result;
}
console.log(weave("weave", 2));
console.log(weave("abcd efgh ijkl m", 5));
You can do this with fewer lines of code:
function weave(word, numSkip) {
word = word.split("");
for (i = 0; i < word.length; i++) {
word[i] = ((i + 1) % numSkip == 0) ? "x" : word[i];
}
return word.join("");
}
var result = weave("weave", 2);
console.log(result);

Factorialize a Number

I'm taking the freecodecamp course one of the exercises it's to create a Factorialize function, I know there is several ways to do it just not sure what this one keeps returning 5
function factorialize(num) {
var myMax = num;
var myCounter = 1;
var myTotal = 0;
for (i = 0; i>= myMax; i++) {
num = myCounter * (myCounter + 1);
myCounter++;
}
return num;
}
factorialize(5);
This is a recursive solution of your problem:
function factorialize(num) {
if(num <= 1) {
return num
} else {
return num * factorialize(num-1)
}
}
factorialize(5)
This is the iterative solution:
function factorialize(num) {
var cnt = 1;
for (var i = 1; i <= num ; i++) {
cnt *= i;
}
return cnt;
}
factorialize(5)
with argument 5, it will return the 5! or 120.
To answer your question, why your function is returning 5:
Your function never reaches the inner part of the for-loop because your testing if i is greater than myMax instead of less than.
So you are just returning your input parameter which is five.
But the loop does not calculate the factorial of num, it only multiplies (num+1) with (num+2);
My solution in compliance with convention for empty product
function factorializer(int) {
if (int <= 1) {
return 1;
} else {
return int * factorializer(int - 1);
}
}
Here is another way to solve this challenge and I know it is neither the shortest nor the easiest but it is still a valid way.
function factorialiaze(num){
var myArr = []; //declaring an array.
if(num === 0 || num === 1){
return 1;
}
if (num < 0){ //for negative numbers.
return "N/A";
}
for (var i = 1; i <= num; i++){ // creating an array.
myArr.push(i);
}
// Reducing myArr to a single value via .reduce:
num = myArr.reduce(function(a,b){
return a * b;
});
return num;
}
factorialiaze(5);
Maybe you consider another approach.
This solution features a very short - cut to show what is possible to get with an recursive style and a implicit type conversion:
function f(n) { return +!~-n || n * f(n - 1); }
+ convert to number
! not
~ not bitwise
- negative
function f(n) { return +!~-n || n * f(n - 1); }
var i;
for (i = 1; i < 20; i++) {
console.log(f(i));
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this function
const factorialize = (num) => num === 0 ? 1 : num * factorialize(num-1)
Use it like this:
factorialize(5) // returns 120
Try this :
function factorialize(num) {
var value = 1;
if(num === 1 || num ===0) {
return value;
} else {
for(var i = 1; i<num; i++) {
value *= i;
}
return num * value;
}
}
factorialize(5);
// My solution
const factorialize = num => {
let newNum = 1;
for (let i = 1; i <= num; i++) {
newNum *= i
}
return newNum;
}
I love syntactic sugar, so
let factorialize = num => num <= 1 ? num : num * factorialize(num -1)
factorialize(5)

Categories

Resources