looping through split numbers javascript - javascript

I have this function, I want to loop through both of the strings and
receive a return value for compareNumber that's closest to it - that is (compareNumber +1) but only if none of it's digits are equal to any of searchNumber's digits. If any of compareNumber's digits are equal to any of searchNumber's digits, I need to fins the first value bigger than compareNumber that's not equal to any of searchNumber's digits.
function compareNumbers(searchNumber, compareNumber){
var isEqual = true;
var digitsCompare = compareNumber.toString().split('');
searchNumber.toString().split('').forEach(function(num,index) {
if(!(num===digitsCompare[index])){
isEqual = false;
}
});
return isEqual;
}
var b = compareNumbers(123,124);
console.log(b);
var d = compareNumbers(123,123);
console.log(d);

I think it would be best to consider this mathematically, as opposed to just adding 1 forever until you find a number that works.
The solution below iterates through each individual digit, increasing it by 1 until we find a digit we're allowed to use. Once we make that change, we know the rest of the digits will be replaced with the lowest number available to us.
Think of it like a combination lock, except as soon as you turn one dial, all the ones after it reset to the lowest number we're allowed to use.
function compareNumbers(n1, n2) {
var n1Array = ("" + n1).split("").map(Number);
var n2Array = ("" + n2).split("").map(Number);
var availableNumbers = [...Array(10).keys()].filter(n => !n1Array.includes(n));
//Loop through each digit in our compare string
n2Array.some((n, index) => {
let originalN = n;
//Increment it until we have a valid number
while (!availableNumbers.includes(n))
if (n < 9) n++
else {
//If we've passed 9, then we need to use the lowest number *twice*
//However, if we're changing the first number, we CAN'T replace it with a 0
n = Number((index === 0 ? availableNumbers[0] || availableNumbers[1] : availableNumbers[0]).toString() + availableNumbers[0]);
break;
}
if (originalN !== n) {
n2Array[index] = n;
var replacements = n2Array.splice(index + 1).map(n => availableNumbers[0]);
n2Array = [...n2Array, ...replacements];
return true; //Exit early
}
return false; //Keep iterating
});
//Turn [4,0,0] into 400
return Number(n2Array.join(""));
}
let result1 = compareNumbers(123,124);
console.log(result1);
let result2 = compareNumbers(123,423);
console.log(result2);
A lot of the scrappy/ugly stuff is to account for edge-cases.
The first edge-case being that if we increase a 9, then it shouldn't become a 10, but rather the lowest number available to us repeated twice.
However, there is an edge-case within that. If our lowest number available is 0, and 9 is our first number, we can't replace it with 00. Otherwise, you could end up with 915 becoming 0015.

The code is below:
function compareNumbers(searchNumber, compareNumber) {
//error check the args
var searchString = searchNumber + "";
var compareString = compareNumber + "";
if (compareString.length === 0) return "nope";
var compareInt = parseInt(compareString) + 1;
if (searchString.length === 0) {
return compareInt;
}
//don't crash the app
if (searchString.length >= 10
&& searchString.indexOf("0") >= 0 && searchString.indexOf("1") >= 0
&& searchString.indexOf("2") >= 0 && searchString.indexOf("3") >= 0
&& searchString.indexOf("4") >= 0 && searchString.indexOf("5") >= 0
&& searchString.indexOf("6") >= 0 && searchString.indexOf("7") >= 0
&& searchString.indexOf("8") >= 0 && searchString.indexOf("9") >= 0 ) {
return "nope";
}
while(containsDigits(searchString, compareInt)) {
compareInt++;
}
return compareInt;
}
function containsDigits(digits, intVal) {
var strVal = intVal + "";
var strDigits = digits + "";
for(var i = 0; i < strDigits.length; i++) {
if (strVal.indexOf(strDigits.charAt(i)) >= 0) {
return true;
}
}
return false;
}
// Examples
pairs = [[123, 124], [11, 13], [25, 35], [15, 21], [138, 546], [1, 2], [1, 1]];
pairs.forEach((pair) => console.log(`Compare [${pair[0]}, ${pair[1]}]: ${compareNumbers(pair[0], pair[1])}`));

You don't need to split a string to access its contents as an array.
var digitsCompare = compareNumber.toString();
console.log(digitsCompare.charAt(0)); <-- first char

Related

JavaScript: LeetCode 'Plus One' recursion timeout problem

Plus one- leetcode problem
Problem:
You are given a large integer represented as an integer array digits,
where each digits[i] is the ith digit of the integer. The digits are
ordered from most significant to least significant in left-to-right
order. The large integer does not contain any leading 0's.
Increment the large integer by one and return the resulting array of digits.
Example 1:
Input: digits = [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.
Incrementing by one gives 123 + 1 = 124.
Thus, the result should be [1,2,4].
Example 2:
Input: digits = [9]
Output: [1,0]
Explanation: The array represents the integer 9.
Incrementing by one gives 9 + 1 = 10.
Thus, the result should be [1,0].
Constraints:
1 <= digits.length <= 100
0 <= digits[i] <= 9
digits does not contain any leading 0's.
My solution:
// [9] becomes [1,0]
var plusOne = function(digits) {
let len = digits.length;
//count array backwards
for(let i = len-1; i >= 0; i--) {
// if the currently indexed value is 9, we will zero it (line 14)
// we will also check if the previous entry is 9 via recursion (line 19)
// if it is not 9, we increment it by 1 and return 'digits' (lines 22, 23)
// if there is no previous entry we prepend one and return 'digits' (lines 16, 17)
if(digits[i] == 9) {
digits[i] = 0;
if(!digits[i - 1]){
digits.unshift(1);
return digits;
} else {
plusOne(digits.slice(0, i-1));
}
} else {
digits[i] = digits[i] + 1;
return digits;
}
}
};
let array = [9,9,9];
console.log(plusOne(array));
// This code breaks on input:
// [9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9]
The difficulty with this problem is with 9's, which naturally increment the place value of its more significant neighbor.
I address this problem with recursion. (As you can read in the code comments).
The problem is that I am getting a 'Time limit exceeded' error on Leetcode on the following input:
[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9].
Though it appears to pass all other test cases.
Is this a stack size issue? Is there a way to optimize the space complexity of the above code?
Thank you very much.
I have no idea how to reduce the time/space complexity of the problem as I am new to recursion.
"Is there a way to optimize the space complexity of the above code?"
Yes, remove the unnecessary recursive call. It does nothing:
// [9] becomes [1,0]
var plusOne = function(digits) {
let len = digits.length;
//count array backwards
for(let i = len-1; i >= 0; i--) {
// if the currently indexed value is 9, we will zero it (line 14)
// we will also check if the previous entry is 9 via recursion (line 19)
// if it is not 9, we increment it by 1 and return 'digits' (lines 22, 23)
// if there is no previous entry we prepend one and return 'digits' (lines 16, 17)
if(digits[i] == 9) {
digits[i] = 0;
if(i === 0){
digits.unshift(1);
return digits;
}
} else {
digits[i] = digits[i] + 1;
return digits;
}
}
};
let array = [9,9,9];
console.log(plusOne(array));
There's no need to traverse the entire input. The function can stop as soon as there's no carry to the next decimal place.
var plusOne = function(digits) {
// a single digit add that returns [sum, carry]
const incr = num => num === 9 ? [0, 1] : [num + 1, 0];
// reverse the input so we can go least significant to most
const reversed = digits.reverse();
let index = 0,
carry = 0,
sum = 0;
// increment digits, stopping as soon as there's no carry
// worst case is a run through a lot of 9s
do {
[sum, carry] = incr(reversed[index]);
reversed[index] = sum;
} while (carry && ++index < reversed.length)
// push a 1 if we got to the most significant digit with a carry
if (carry) reversed.push(1);
return reversed.reverse();
}
// here it is running pretty fast on 10x the largest input
let lottaNines = Array(1000).fill(9);
console.log(plusOne(lottaNines))
you can do that :
const plusOne = arr =>
{
let
rem = 1
, res = []
;
for (let i=arr.length-1; i >= 0; i--)
{
res[i] = arr[i] + rem;
rem = res[i] > 9 ? 1 : 0;
if (rem)
res[i] = 0;
}
if (rem )
res.unshift(1);
return res;
}
console.log( JSON.stringify(plusOne([1,2,3])))
console.log( JSON.stringify(plusOne([9])))
const outOfMaxInteger =[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9]
console.log( JSON.stringify(plusOne(outOfMaxInteger)))
in fact it amounts to making a school addition:
const arrAdd= (arrA,arrB) =>
{
let
iA = arrA.length -1
, iB = arrB.length -1
, res = []
, rem = 0
;
for (let i = 1 + Math.max(iA,iB); i--; iA--,iB--)
{
res[i] = rem + (iA<0?0:arrA[iA]) + (iB<0 ? 0:arrB[iB]);
rem = 0 | (res[i] / 10);
res[i] %= 10;
}
if (rem) res.unshift(rem);
return res;
}
console.log( ' [1,2,3] + [1] =', JSON.stringify(arrAdd( [1,2,3], [1])))
console.log( '[1,2,3,0] + [8,0] =', JSON.stringify(arrAdd( [1,2,3,0],[8,0])))
console.log( ' [1,9,3] + [8] =', JSON.stringify(arrAdd( [1,9,3], [8])))
console.log( ' [9] + [9] =', JSON.stringify(arrAdd( [9], [9])))

Codwars: Array to single value +1

Given an array of integers of any length, return an array that has 1 added to the value represented by the array.
the array can't be empty
only non-negative, single digit integers are allowed
Return nil (or your language's equivalent) for invalid inputs.
Examples
For example the array [2, 3, 9] equals 239, adding one would return the array [2, 4, 0].
My code so far:
function upArray(arr){
let i = parseInt(arr.join('')) + 1;
return arr.some(e => typeof e !== 'number' || e < 0) ?
null : i
.toString()
.split('')
.map(e => parseInt(e));
};
It seems to pass most basic test however fails with larger inputs. Where have I gone wrong?
Just like you have converted the array into a number, you have to convert the number back into an array.
function upArray(arr){
let i = parseInt(arr.join('')) + 1;
return i.toString().split('').map(x => parseInt(x));
};
console.log(upArray([2,3,9]));
Your code won't work if the array length is greater than 100k...
Number type of javascript or any language is not enough big to handle it.
It's better if we calculate the last element with 1. If result is larger than nice ( < 10 ),
we continue to calculate next element with 1 and assign current value to 0. If result is smaller or equal 9, just assign the result to current and exit loop.
Then we print the final array as result:
pseudo code:
for i from: n-1:0
result = arr[i] + 1;
if(result < 10) :
arr[i] = result;
exit loop;// no need to continue calculate
else:
arr[i] = 0;
endif;
endfor;
You can join final array as string.
Here's probably the fastest solution (performance wise) - also there's no need to deal with BigInt, NaN, or Infinity:
function upArray(arr) {
if (!isInputIsNonEmptyArray(arr)) {
return null;
}
const isNumber = num => typeof num === 'number';
const isIntSingleDigit = num => Number.isInteger(num) && num >= 0 && num <10;
let resultArr = [];
let i = arr.length;
let num;
while (i-- > 0) {
num = arr[i];
if (!isNumber(num) || !isIntSingleDigit(num)) {
return null;
}
if (num === 9) {
resultArr[i] = 0;
if (i === 0) { //means we're in the msb/left most digit, so we need to insert 1 to the left
resultArr.unshift(1);
break; //you can leave it out really, as the next check in the while will fail anyway
}
}
else {
resultArr[i] = num + 1; //No more + 1 should be made, just check for validity
//of the rest of the input and copy to the result arr
while (--i > -1) {
num = arr[i];
if (!isNumber(num) || !isIntSingleDigit(num)) {
return null;
}
resultArr[i] = arr[i];
}
break;
}
}
return resultArr;
function isInputIsNonEmptyArray(arr) {
return Array.isArray(arr) && arr.length > 0;
}
}
If the input arg is not an array or an empty array, or if you encounter invalid element during the main while loop you return null.
In the main while loop you go from the right most element (lsd), and add 1 to it (or insert 0 if the number is 9) up the the left most digit.
If a number which is less than 9 is incremented, no need to increment any more (this is the while loop in the else clause).

How Can I find the first number greater than const M?

I have a problem with this. I have to find the first prime number greater than my const M.
For example, I have M = 11, and I have to find the first prime number greater than M and it is 13.
How Can I do that?
// isPrime
const M = 11
function isPrime(num) {
if (num < 2) return false;
for (let i = 2; i < num; i++) {
if (num % i == 0) return false;
}
return true;
}
console.log(isPrime(M))
And I would like find for M = 11, primeNumber = 13, for M = 15, primeNumber = 17 etc.
You can iterate from M+1 until you find your prime number. You can do the following,
function isPrime(num) {
if (num < 2) return false;
for (let i = 2; i < num; i++) {
if (num % i == 0) return false;
}
return true;
}
findGreaterPrime = (m) => {
let i = m+1;
let found = false;
while(!found) {
if(isPrime(i)) {
found = true;
return i;
}
i++;
}
}
console.log(findGreaterPrime(11));
console.log(findGreaterPrime(13));
By the way, this method will be very slow for larger numbers. You can use some fast prime generators. You can follow the answers in this thread.
Simple and fast solution, via prime-lib (I'm the author).
The example below generates 2 primes, starting with 7 and upward:
import {generatePrimes, stopOnCount} from 'prime-lib';
const i = generatePrimes({start: 7}); // infinite prime-iterator
const s = stopOnCount(i, 2); // stop-iterator
const values = [...s]; // 7, 11
It checks if start is a prime, to be included then. If you need only a prime that follows, just check if the first number matches your M number, then take the next one instead:
if(values[0] === M) {
// use values[1]
} else {
// use values[0]
}

How to find a first occurrence of double digit number

So, I am pushing elements into array through prompt until getting 0. After that I am trying to find the first double digit number. For example if the array is [2,3,55,0] my program should return 55.
function findFirstDouble() {
var niz = []
var a = 1;
for (var i = 1; a != 0; i++) {
var unos = parseInt(prompt("Enter number :"))
niz.push(unos)
a = unos
}
alert(niz);
for (var i = 0; i < niz.length; i++) {
if (niz[i] / 10 > 0 && niz[i] / 100 == 0) {
console.log(niz[i]);
break;
}
else {
alert("No double digit numbers!")
break;
}
}
}
findFirstDouble();
Please use built in js function find.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Here is the solution
// I assume that you already have an array
const niz = [2,3,55,0]
const firstDoubleDigit = niz.find(num => num < 100 && num >= 10)
console.log(firstDoubleDigit)
Here is the answer I think you are looking for.
I omitted the array filling part.
Why would you do any kind of division if you just need to check every number and if the first one matches the criteria then you've got your double digit number hence exit the loop with break or return keyword.
var niz = [1, 2, 55, 13];
for (var i = 0; i < niz.length; i++) {
if (niz[i] > 9 && niz[i] < 100) {
console.log('Pronadeni broj je:', niz[i]);
break;
}
}
You can also convert to string: if (niz[i].toString().length===2){ // your number }
Easy way without math is just to convert it to a string.
const data = [2,3,55,0];
const res = data.findIndex(n=>`${n}`.length===2);
console.log(res > -1 ? "Exists at position " + res : "Doesn't exist");
Mathematically:
const data = [2,111,3,55,0];
const res = data.find(n=>n<100&&n>9);
console.log(res ? "Exists " + res : "Doesn't exist");

Get Number of Decimal Places with Javascript

How would I calculate the number of decimal places (not digits) of a real number with Javascript?
function countDecimals(number) {
}
For example, given 245.395, it should return 3.
Like this:
var val = 37.435345;
var countDecimals = function(value) {
let text = value.toString()
// verify if number 0.000005 is represented as "5e-6"
if (text.indexOf('e-') > -1) {
let [base, trail] = text.split('e-');
let deg = parseInt(trail, 10);
return deg;
}
// count decimals for number in representation like "0.123456"
if (Math.floor(value) !== value) {
return value.toString().split(".")[1].length || 0;
}
return 0;
}
countDecimals(val);
The main idea is to convert a number to string and get the index of "."
var x = 13.251256;
var text = x.toString();
var index = text.indexOf(".");
alert(text.length - index - 1);
Here is a method that does not rely on converting anything to string:
function getDecimalPlaces(x,watchdog)
{
x = Math.abs(x);
watchdog = watchdog || 20;
var i = 0;
while (x % 1 > 0 && i < watchdog)
{
i++;
x = x*10;
}
return i;
}
Note that the count will not go beyond watchdog value (defaults to 20).
I tried some of the solutions in this thread but I have decided to build on them as I encountered some limitations. The version below can handle: string, double and whole integer input, it also ignores any insignificant zeros as was required for my application. Therefore 0.010000 would be counted as 2 decimal places. This is limited to 15 decimal places.
function countDecimals(decimal)
{
var num = parseFloat(decimal); // First convert to number to check if whole
if(Number.isInteger(num) === true)
{
return 0;
}
var text = num.toString(); // Convert back to string and check for "1e-8" numbers
if(text.indexOf('e-') > -1)
{
var [base, trail] = text.split('e-');
var deg = parseInt(trail, 10);
return deg;
}
else
{
var index = text.indexOf(".");
return text.length - index - 1; // Otherwise use simple string function to count
}
}
You can use a simple function that splits on the decimal place (if there is one) and counts the digits after that. Since the decimal place can be represented by '.' or ',' (or maybe some other character), you can test for that and use the appropriate one:
function countPlaces(num) {
var sep = String(23.32).match(/\D/)[0];
var b = String(num).split(sep);
return b[1]? b[1].length : 0;
}
console.log(countPlaces(2.343)); // 3
console.log(countPlaces(2.3)); // 1
console.log(countPlaces(343.0)); // 0
console.log(countPlaces(343)); // 0
Based on Gosha_Fighten's solution, for compatibility with integers:
function countPlaces(num) {
var text = num.toString();
var index = text.indexOf(".");
return index == -1 ? 0 : (text.length - index - 1);
}
based on LePatay's solution, also take care of the Scientific notation (ex: 3.7e-7) and with es6 syntax:
function countDecimals(num) {
let text = num.toString()
if (text.indexOf('e-') > -1) {
let [base, trail] = text.split('e-')
let elen = parseInt(trail, 10)
let idx = base.indexOf(".")
return idx == -1 ? 0 + elen : (base.length - idx - 1) + elen
}
let index = text.indexOf(".")
return index == -1 ? 0 : (text.length - index - 1)
}
var value = 888;
var valueLength = value.toString().length;

Categories

Resources