how to build count and say problem in javascript - javascript

I am trying to solve the below problem in JavaScript
The count-and-say sequence is the sequence of integers beginning as follows:
1, 11, 21, 1211, 111221, ...
1 is read off as one 1 or 11.
11 is read off as two 1s or 21.
21 is read off as one 2, then one 1 or 1211.
Given an integer n, generate the nth sequence.
Note: The sequence of integers will be represented as a string.
Example:
if n = 2,
the sequence is 11.
So I want to create a function which pass N integer and gives it value
Here is my code:
let countAndSay = function (A) {
if (A == 1) return "1"
if (A == 2) return "11"
let str ="11"
if(A > 2){
// count
}
}
I don't understand the logic for how to build this.

You need to be able to dynamically determine the number and type of chunks a string has, which can be done pretty concisely with a regular expression. To come up with the string to deconstruct on index n, recursively call countAndSay to get the result of n - 1:
let countAndSay = function (count) {
if (count === 1) {
return '1';
}
const digitsArr = countAndSay(count - 1).match(/(\d)\1*/g);
// You now have an array of each chunk to construct
// eg, from 1211, you get
// ['1', '2', '11']
return digitsArr // Turn the above into ['11', '12', '21']:
.map(digitStr => digitStr.length + digitStr[0])
.join(''); // Turn the above into '111221'
};
console.log(
countAndSay(1),
countAndSay(2),
countAndSay(3),
countAndSay(4),
countAndSay(5),
);

Here's a function that generates the next string of numbers based on the previous string you feed it:
function next(s) {
s = s + "*"; // add a flag value at the end of the string
var output = "";
var j = 0;
for (var i = 1; i < s.length; i++) {
if (s.charAt(i) != s.charAt(i - 1)) { // if the character changes, concatenate the amount (i - j) and the digit
output += (i - j) + s.substring(j, j+1);
j = i;
}
}
return output;
}
Then you'd need to recursively run next N times.

Related

Number of 1 Bits with Javascript

Question: Write a function that takes an unsigned integer and returns the number of '1' bits it has (also known as the Hamming weight).
Example 1:
Input: n = 00000000000000000000000000001011
Output: 3
Explanation: The input binary string 00000000000000000000000000001011 has a total of three '1' bits.
My Code
var hammingWeight = function(n) {
for (i=0; i<32; i++) {
var mask = 1;
var count = 0;
if ((mask & n) != 0 ) {
mask <<= 1;
count++;
}
return count;
}
};
Test Case:
00000000000000000000000000001011
00000000000000000000000010000000
11111111111111111111111111111101
Expected Output:
3
1
31
Output:
1
0
1
What did I do wrong with my code?
You have a few issues here:
You are redefining count and mask inside of your for loop.
You are returning after the first iteration of the loop, instead of waiting for the whole thing to count up.
You only shift mask if a bit is 1.
Here is a corrected function:
var hammingWeight = function(n) {
var count = 0;
var mask = 1;
for (i=0; i<32; i++) {
if ((mask & n) != 0 ) {
count++;
}
mask <<= 1;
}
return count;
};
A shorter way to write this could be:
const hammingWeight = value => [...value].filter(f => f == 1).length;
Explanation:
[...value] this will create an array of 0's and 1's based on your string
.filter(f => f == 1) will filter the array, keeping only the 1 values
.length gives you the length of the filtered array

How to build a function that searches for string occurrences?

I need help Writing a function subLength() that takes 2 parameters, a string and a single character. The function should search the string for the two occurrences of the character and return the length between them including the 2 characters. If there are less than 2 or more than 2 occurrences of the character the function should return 0. How can I solve this problem using loops?
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
Here I loop through the characters of the string to find each value that is the char.
if the length isn't 2, return 0.
using slice, get only the characters within the two found indexs and get that length adding one to fix the offset
const subLength = (str, char) => {
let strChars = str.toLowerCase().split(""),
found = [],
length = 0;
strChars.forEach((val, index) => {
if (val === char) {
found.push(index);
}
});
if (found.length != 2) {
return length;
}
return str.slice(found[0], found[1]).length + 1;
}
console.log(subLength('Saturday', 'a')); // returns 6
console.log(subLength('summer', 'm')); // returns 2
console.log(subLength('digitize', 'i')); // returns 0
console.log(subLength('cheesecake', 'k')); // returns 0
You can try this logic:
Loop over string and count number of occurance
if count is 2,
Create a regex to capture the string in between.
Return its length
Else return 0
function subLength(str, char) {
let length = 0;
const occuranceCount = Array
.from(str)
.filter((c) => c.toLowerCase() === char.toLowerCase())
.length
if (occuranceCount === 2) {
const regex = new RegExp(`${char}(.*)${char}`)
length = str.match(regex)[0].length
}
console.log(length)
return length;
}
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
Using just for loop:
function subLength(str, char) {
let count = 0;
let initPosition;
let lastPosition;
for (let i = 0; i < str.length; i++) {
if (str[i] === char) {
count++
if (count > 2) {
return 0;
}
if (initPosition === undefined) {
initPosition = i
} else {
lastPosition = i+1
}
}
}
return count < 2 ? 0 : lastPosition - initPosition;
}
console.log(subLength('Saturday', 'a')); // returns 6
console.log(subLength('summer', 'm')); // returns 2
console.log(subLength('digitize', 'i')); // returns 0
console.log(subLength('cheesecake', 'k')); // returns 0
I too am going through the Codecademy course where this question came up which led me to this post.
Using the RegExp solution provided by #Rajesh (thank you!!) I started to break it down to better understand what was going on and making notes/comments because I am still pretty new and haven't used or been exposed to some of these things.
At the end of it all I thought I'd share what I ended up with in case anyone found it helpful.
function subLength(str, char) {
// Outputting to the console what we are looking for given the value of the string and character from the test cases at the end of this script.
console.log(`Showing the subLength for the string: "${str}" between "${char}" and "${char}" including the "${char}" positions.`);
// create the length variable which will be returned by the function
let length = 0;
// ** Search the string for the two occurrences of the character and count them. Then assign the result to the occurrenceCount variable for use in the if else statement.
// The "Array" class is a global object that is used in the construction off arrays.
// The Array.from() static method creates a new, shallow-copied Array instance from an array-like or iterable object.
// The Array.filter() method creates a new array with all elements that pass the test implemented by the provided function. The "c" represents each element of the array/string which is then compared to the char variable. if it is a match it gets added to the Array. We use .toLowerCase on both to ensure case compatibility.
// Appending the Array with ".length" assigns occurrenceCount the numeric value of the array's length rather than the array of characters.
const occurrenceCount = Array.from(str).filter((c) => c.toLowerCase() === char.toLowerCase());
console.log(' The contents of the occurrenceCountArray = ' + occurrenceCount);
console.log(' The character occurrence count = ' + occurrenceCount.length);
// if the string has two occurrences : return the length between them including the two characters : else the string has less than 2 or more than 2 characters : return 0.
if (occurrenceCount.length === 2) {
// The RegExp object is used for matching text with a pattern. The "(.*)" in between the ${char}'s will match and capture as much as possible aka greedy match. "()" = capture anything matched. (" = start of group. "." = match any character. "*" = Greedy match that matches everything in place of the "*". ")" = end of group.
const regex = new RegExp(`${char}(.*)${char}`);
// log to console the pattern being matched
console.log(` regex pattern to find = ${regex}`);
// log to the console the [0] = index 0 pattern that was captured from the string using str.match(regex)[0]
console.log(` regex output = ${str.match(regex)[0]}`);
// Use".length" to count the number of characters in the regex string at index 0 of the regex array and assign that value to the length variable.
length = str.match(regex)[0].length;
// Output the results to the console
console.log(` The distance from "${char}" to "${char}" (including the "${char}" positions) in the string: ${str} = ${length}\n`);
// return the length value
return length;
} else {
// Output the results to the console
console.log(` The string either has too many or too few occurrences.\n The subLength = ${length}\n`);
// return the length value
return length;
}
}
// test cases
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
The answer I am getting is this:
const subLength = (str, char) => {
let charCount = 0;
let len = -1;
for (let i=0; i<str.length; i++) {
if (str[i] == char) {
charCount++;
if (charCount > 2) {
return 0;
}
if (len == -1) {
len = i;
} else {
len = i - len + 1
}
}
}
if (charCount < 2) {
return 0;
}
return len;
};
It is better to try yourself a solution first. It is a very bad practice to just ask a solution for your homework!!!
Even if the solution can be JUST a few lines of code i wrote for you with commments a working solution :
const subLength = (str,char) => {
// create an empty array
const strarr = [];
// push string into array
strarr.push(str);
//initiate a count variable
let count = 0;
// WRITE YOUR REGULAR EXPRESSION
// Using the regular expression constructor - new RegExp("ab{2}", "g") .
const regString = `[${char}]`;
const regex = new RegExp(regString, "g");
// iterate through the string array to
for (let i = 0; i < strarr.length; i++) {
// calculate how many time the character occurs
count = (strarr[i].match(regex) || []).length;
};
// check with if condition
//if count is 2
if (count === 2) {
// calculate the index of first ocurrance of the string
first = str.indexOf(char);
// calculate the index of second ocurrance of the string
second = str.lastIndexOf(char);
// calculate the distance between them
return second - first + 1;
// if count is greater than two return 0
}
else if (count > 2) {
return count = 0;
}
// if count is less than two return 0
else if (count < 2) {
return 0;
}
};
console.log(subLength("iiiiliiile","l"));
I just answered this problem in codeAcademy and this is the solution that I came up with, just using if-statements and string.indexOf
const subLength = (strng, char) => {
let firstIndex = strng.indexOf(char);
let secondIndex = strng.indexOf(char, (firstIndex + 1));
let thirdIndex = strng.indexOf(char, (secondIndex + 1));
if (firstIndex === -1){
return 0
} else if (secondIndex === -1){
return 0
} else if (thirdIndex === -1 ){
return (secondIndex - firstIndex + 1)
} else {
return 0
};
};

Multiplicative Persistence Codewars Challenge

I've been working on a kata from Codewars, the challenge is to write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
Example:
persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number
While trying to figure this out I came across a solution online (shown below) and after trying to understand its logic, I couldn't see why the code didn't work
var count = 0;
function persistence(num) {
if (num.toString().length === 1) {
return count;
}
count++;
var mult = 1;
var splitStr = num.toString().split("");
for (var i = 0; i <= splitStr; i++) {
mult *= parseFloat(splitStr[i])
}
return persistence(parseFloat(mult));
}
The output for any single digit number will be 0 which is correct however for any number that is multiple digits, the persistence always logs as 1 and I can't seem to figure out why, any help would be greatly appreciated.
The posted code has quite a few problems.
for (var i = 0; i <= splitStr; i++) {
But splitStr is an array, not a number; i <= splitStr doesn't make sense. It should check against splitStr.length instead of splitStr.
Another problem is that it should use i <, not i <=, else the final splitStr[i] will be undefined.
Another problem is that the count variable is global, so more than one call of persistence will result in inaccurate results. There's no need for a count variable at all. To fix it:
function persistence(num) {
if (num.toString().length === 1) {
return 0;
}
var mult = 1;
var splitStr = num.toString().split("");
for (var i = 0; i < splitStr.length; i++) {
mult *= parseFloat(splitStr[i])
}
return 1 + persistence(parseFloat(mult));
}
console.log(
persistence(999),
persistence(39),
persistence(4)
);
Or, one could avoid the for loop entirely, and use more appropriate array methods:
function persistence(num) {
const str = num.toString();
if (str.length === 1) {
return 0;
}
const nextNum = str.split('').reduce((a, b) => a * b, 1);
return 1 + persistence(nextNum);
}
console.log(
persistence(999),
persistence(39),
persistence(4)
);
or we can use while loop with reduce array method
const persistence=(num)=>{
let splitNumArr=num.toString().split('')
let newList
let count=0
while(splitNumArr.length>1){
newList=splitNumArr.reduce((acc,curr)=>{
return acc*=curr
})
splitNumArr=newList.toString().split('')
count++
}
return count
}
console.log(persistence(39))===3
console.log(persistence(999))===4
console.log(persistence(9))===0

Check if numbers are in sequence

I have a textbox that contains a max length of 4 and if the user enters the numbers in sequence then needs to throw an error.
Examples: Below are a few examples which need to block:
1234, 4567, 5678, etc
And it can accept 1233, 4568, etc
I'm expecting this condition in Jquery or JavaScript.
Any help would be appreciated
Code: I want to use the code in below format:
$.validator.addMethod('Pin', function (b) {
var a = true;
a = (/^([0-9] ?){4}$/i).test(b);
return a
}, '');
We can replace the condition which is in bold.
The simplest solution would be to use the following code
/**
* The sequential number would always be a subset to "0123456789".
* For instance, 1234, 4567, 2345, etc are all subset of "0123456789".
* To validate, this function uses 'indexOf' method present on String Object.
* you can read more about 'indexOf' at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
*/
$.validator.addMethod("Pin", function(b) {
var numbers = "0123456789";
//If reverse sequence is also needed to be checked
var numbersRev = "9876543210";
//Returns false, if the number is in sequence
return numbers.indexOf(String(b)) === -1 && numbersRev.indexOf(String(b)) === -1;
}, "");
The condition with the variable numbersRev is only needed if the reverse sequence validation is also required
You can simply split the pin into individual digits, and iterate through them to ensure that there is at least one part that is not in sequential order (i.e difference of +2 or more):
$.validator.addMethod("Pin", function(value, element) {
var digits = value.split(''),
invalid = true;
// Iterate through pairs of values
// As long as one comparison is not consecutive, the PIN is valid
for(var i = 0; i < digits.length - 1; i++) {
if (parseInt(digits[i]) - parseInt(digits[i+1]) > 1) {
invalid = false;
break;
}
}
return !invalid;
}, "");
If you want to also accommodate for cases of descending sequences, i.e. 9876, simply check for the absolute difference between one digit to another, i.e.:
Math.abs(parseInt(digits[i]) - parseInt(digits[i+1])) > 1
Proof-of-concept logic:
// Test values
var values = ['1234', '1235', '4321', '5321'];
for(var v = 0; v < values.length; v++) {
var value = values[v],
digits = value.split(''),
invalid = true;
for(var i = 0; i < digits.length - 1; i++) {
if (Math.abs(parseInt(digits[i]) - parseInt(digits[i+1])) > 1) {
invalid = false;
break;
}
}
console.log('PIN: ' + value + '. Valid? ' + !invalid);
}
You can do like this:
//with array
var numArray = [1234, 1243];
for (var i = 0; i < numArray.length; i++) {
checkIfSequential(numArray[i]);
}
//with string
var numberGiven = 1234;
checkIfSequential(numberGiven);
function checkIfSequential(num) {
var newNum = num + ''
newNum = newNum.split('');
console.log(num + ': ' + newNum.every((num, i) => i === newNum.length - 1 || num < newNum[i + 1]));
}
I get your point,
Why dont you just set the max length of the input field in the HTML itself and then bind a keyup event to the input box to trigger the validation ?
ex:
<input type="text" maxlength="4" onkeyup="validateMe()" id="key"/>
<script>
validateMe = function(){
if(document.getElementById("key").value == "1234"){
alert("yay! Key accepted!!");
}
};
</script>
In order to fulfill the requirements for max length of 4 digits.
We enumerate all possible sequential digits according to the OP constraints [1234, 2345, 3456, 4567, 5678, 6789], and then check them with the input arguments.
const sequentialDigits = (input) => {
const allSeqNumsArr = [1234, 2345, 3456, 4567, 5678, 6789];
return allSeqNumsArr.filter((num) => num === input).length > 0;
};
console.log(sequentialDigits(1234));
console.log(sequentialDigits(1235));
console.log(sequentialDigits(5321));

Permutations filtered with no repeating characters

This is a task from freeCodeCamp.
My goal is to create a function which:
Takes any string with any characters.
Creates an array with all the permutations possible out of that string.
Filters the array and returns only the strings which don't have repeated consecutive letters.
Return the number of total permutations of the provided string that don't have repeated consecutive letters. Assume that all characters in
the provided string are each unique. For example, aab should return 2
because it has 6 total permutations (aab, aab, aba, aba, baa, baa),
but only 2 of them (aba and aba) don't have the same letter (in this
case a) repeating.
I can't figure out what have i wrote wrong. I think the problem lies either in the filter function or the permutation list is faulty.
function permAlone(str) {
if (str.length == 1) {
return str;
}
// Creates all possible Permutations and pushes to an array
var arr = [];
var p = 0; // position of the element which needs to be swapped
// Loop count equal to number of Permutations.
var loops = factorialize(str.length);
for (var i = 0; i < loops; i++) {
// if the position is not the last element in the strig keep swapping with next following character
if (p != str.length - 1) {
var splitStr = str.split('')
arraySwapElements(splitStr, p, p + 1);
str = splitStr.join('');
arr.push(str);
p += 1;
// when position is at the last index, change position to 0
} else {
p = 0;
i -= 1;
}
}
// swaps 2 items in an array
function arraySwapElements(arr, a, b) {
var item = arr[a];
arr[a] = arr[b];
arr[b] = item;
};
// outputs a factorial of a number
function factorialize(num) {
if (num === 0) {
return 1;
} else {
return num * factorialize(num - 1);
}
}
// filters any array which has 2 or more repeating characters
var x = arr.filter(function(str) {
var re = /(.)\1+/;
var result = re.test(str);
if (!result) {
return str;
}
})
// returns the filtered arrays length
return x.length
}
console.log(permAlone('abfdefa'));
When testing:
permAlone("aab") should return a number. // Correct
permAlone("aab") should return 2. // Correct
permAlone("aaa") should return 0. // Correct
permAlone("aabb") should return 8. // Correct
permAlone("zzzzzzzz") should return 0.// Correct
permAlone("a") should return 1.// Correct
permAlone("aaab") should return 0.// Correct
permAlone("abcdefa") should return 3600. // Incorrect
permAlone("abfdefa") should return 2640.// Incorrect
permAlone("aaabb") should return 12. // Incorrect
The issue stems from the logic used in the for loop. While the loop does generate the right number of total permutations, it doesn't generate all permutations.
For example, if our string to be permuted was "abcd", the swapping mechanism would generate strings like this:
bacd bcad bcda
cbda cdba cdab
dcab dacb dabc
adbc abdc abcd
Uh oh! That last arrangement is the same as the starting string. When we start swapping again, we're going to get the same set that we did on the first pass. We're never going to get a permutation like "acbd". Thus the resulting array contains higher numbers of some permutations and lower numbers of others.
I'm not sure how to fix it with the approach you're using, but a recursive function to get permutations could be written like this:
// Returns an array of all permutations of a string
function getPerms(str) {
// Base case. If the string has only one element, it has only one permutation.
if (str.length == 1) {
return [str];
}
// Initialise array for storing permutations
let permutations = [];
// We want to find the permutations starting with each character of the string
for (let i = 0; i < str.length; i++) {
// Split the string to an array
let splitStr = str.split('');
// Pull out the character we're checking for permutations starting with
let currentElem = splitStr.splice(i, 1)[0];
// Get permutations of the remaining characters
let subPerms = getPerms(splitStr.join(''));
// Concat each of these permutations with the character we're checking
// Add them to our list
subPerms.forEach(function (combination) {
permutations.push(currentElem.concat(combination));
});
}
// return our list
return combinations;
}

Categories

Resources