JavaScript: LeetCode 'Plus One' recursion timeout problem - javascript

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])))

Related

How to generate natural numbers not less than X and not more than Y, consisting of the same digits?

Please help me understand the algorithm. It is necessary to generate natural numbers not less than X and not more than Y, consisting of the same digits. Memory limit 256 MB.
For example, the number 999999 meets this requirement, but the number 123123 does not.
I can't pass the test because I can't reduce my memory usage (565.56 Mb / 256 Mb)
Input data: (1 ≤ l,r ≤ 10**18)
Output data format: The number of numbers in the given range.
For example: r = 10, l = 100. Result 9 (11, 22, 33, 44, 55, 66, 77, 88, 99)
function numberOfTests(l, r) {
let count = 0;
for (let i = l; i <= +r; i++) {
let el = String(i).split("");
el = [el.every((e, i, a) => e === a[0])];
if (!el.includes(false)) {
count++;
}
}
return count;
}
console.log(numberOfTests("10 100")); // 9
console.log(numberOfTests("4 7")); // 4
You can try this:
const x= 200 // example
const y = 990 // example
const sameDigit = (num) => {
let first = num % 10;
while (num) {
if (num % 10 !== first) return false;
num = Math.floor(num / 10);
}
return true
}
for (i=x+1; i < y; i++){
if (sameDigit(i)) console.log(i)
}
You can have a function called sameDigits that checks each digit of a number to be the same. We call this function in our forloop each time we are checking a number and if the condition was true, we simply log that number.
I'm unable to understand the code in the question or access the link. This answer answers the title of the post: get natural numbers between a low and high bound consisting only of repeating digits.
Thinking about it more of a lexical problem than a numeric one: We need to know the order of magnitude and first digit of the low bound, and the order of magnitude and the first digit of the high bound.
Then, it's just loops: from the low order of magnitude, to the high order, all the repeating digits number of that order (clipped to the low and high bounds).
function repeatDigitsFrom(lowBound, highBound) {
const result = []
const lowStr = lowBound.toString().trim()
const highStr = highBound.toString().trim()
for (let order=lowStr.length; order <= highStr.length; order++) {
let startDigit = order === lowStr.length ? lowStr[0] : 1;
let endDigit = order === highStr.length ? highStr[0] : 9;
for (let d = startDigit; d <= endDigit; d++) {
let str = ''.padStart(order, d);
let num = parseInt(str);
// check to clean up the edges
if (num >= lowBound && num <= highBound) result.push(num);
}
}
return result
}
console.log(repeatDigitsFrom(291, 38222))

Given an circular array calculate the diff between two consecutive number. & if diff is greater than ‘k’, print 1 else print 0

Given an circular array & calculate the diff between two consecutive number. & if diff is greater than ‘k’, print 1 else print 0
Input Description:
You are given two numbers ‘n’, ’m’. Next line contains n space separated integers.
Output Description:
Print 1 if the difference is greater than ‘m’.
Can Anyone help with the code for easy Understanding for beginners
Sample Input :
5 15
50 65 85 98 35
Sample Output :
0 1 0 1 0
Code:
let cirluarArray = (data) => {
let n=data[0].split(" ").map(Number);//(sample input 1)
let arr = data[1].split(" ").map(Number);//(sample input 2)
let i,arr1=[];
for(i=0;i<arr.length-1;i++){
let x=arr[i]-arr[i+1];
if((x>0 && x<n[1])||(x<0 && x>-n[1])){
arr1.push(0);
}
else{
arr1.push(1);
}
}
if(((arr[arr.length-1]-arr[0])>0 && (arr[arr.length-1]-arr[0])<n[1])||((arr[arr.length-1]-arr[0])<0 && (arr[arr.length-1]-arr[0])>-n[1])){
arr1.push(0);
}
else{
arr1.push(1);
}
return arr1.join(" ");
};
console.log(cirluarArray(userInput));
I think that is
const circularArray = (array, k) => {
array.push(array.at(0)); // circular array
let output = [];
for (let i = 1; i < array.length; i++) {
const currentNumber = array[i];
const prevNumber = array[i-1];
let diff = currentNumber - prevNumber;
if (diff < 0) {
diff *= -1; // if negative, change to positive
}
if (diff > k) {
output.push(1);
} else {
output.push(0);
}
}
return output;
}
const result = circularArray([50, 65, 85, 98, 35], 15);
console.log(result);

Javascript - How to sum up all the first and last digit of a number until only two digits are left?

I am fairly new to programming, just knowing the basics in Javascript and Swift. I am trying to write a simple program which creates, from any entered number, a two digit number by summing up the first and last digit until only two digits are finally left.
Here is an example:
num = 1234567:
1+7 = 8
2+6 = 8
3+5 = 8
4 remains
So the first result is: 8884. Now everything is added again:
8+8 = 16
8+4 = 12
The result is 1612. Again everything is summed up:
1+2 = 3
6+1 = 7
The result is 37 - which is also the final result.
I am struggling with two things. First the while loop. I was thinking about casting num.toString() and then do a while loop like this in which I change the string to an int again:
num.toString()
while (num.length > 2) {
num = num.parseInt(num, 10);
...
}
But this doesn't work properly, plus it gets crazy complicated I guess because I would have to switch between string and int each new round, right?
I know how to add all digits together until I get a two digit number (it took me a while to figure this one out) and I am not even sure if this is a good way to do it:
var sum = num
.toString()
.split('')
.map(Number)
.reduce(function (a, b) {
return a + b;
}, 0);
But obviously I cannot use this here and I have no idea how to change the code so that the first and last digit are added together.
Slightly different approach:
function sum(num) {
var numString = num.toString();
var newString = "";
while (numString.length > 1) { // (1)
newString += (parseInt(numString[0]) + parseInt(numString[numString.length - 1])).toString(); // (2)
numString = numString.substring(1, numString.length - 1); // (3)
}
newString += numString; // (4)
if (newString.length > 2) { // (5)
console.log(newString)
return sum(newString);
} else {
return newString;
}
}
console.log(sum(1234567));
Outputs:
8884
1216
73
Brief explanation of what's going on:
(1) Your while loop will process the string until there's either 1 or
0 characters left
(2) Add the sum of your first and last character to
your newString
(3) Remove the first and last characters from your
numString now that they've been saved to the newString. Because
you're overwriting the value in numString and shrinking it, this
will eventually satisfy the while condition of a numString with
less than 2 characters
(4) Add the remaining characters to
newString, which will either be 1 or 0 characters depending on the
length of the original number
(5) if your newString is more than 2
characters, run this method again. Otherwise return your result
Try this buddy. Its just using simple for loop. Its loops upto half of number and add corresponding. The final result according to ur logic should be 73 not 37
function sum(num){
//if num is greater than or equal to 2 end the function and return final value
if(num.length <= 2) return num;
//converting the num to string beacuse first time input will be number
num = String(num);
let result = '';
//creating a loop upto half of length of the num
for(let i = 0;i<num.length/2;i++){
//if the number is not middle one
if(i !== num.length - 1 - i)
{
//adding the sum of corresponding numbers to result
result += parseInt(num[i]) + parseInt(num[num.length - 1 - i]);
}
//if the number is middle number just add it to result
else result += num[i]
}
return sum(result);
}
console.log(sum(1234567))
You could take a nested while loop and check the string length for the outer loop and the left and right indices for the inner loop
function add(n) {
var s = n.toString(),
l, r,
sum;
while (s.length > 2) {
l = 0;
r = s.length - 1;
sum = [];
while (l < r) {
sum.push(+s[l++] + +s[r--]);
}
if (l === r) sum.push(s[l]);
s = sum.join('');
}
return +s;
}
console.log(add(1234567));
The same but with a recursive function.
function add(n) {
var s = n.toString(),
l = 0, r = s.length - 1,
sum = [];
if (s.length <= 2) return n;
while (l < r) sum.push(+s[l++] + +s[r--]);
if (l === r) sum.push(s[l]);
return add(+sum.join(''));
}
console.log(add(1234567));

How to stop a For Loop in a middle and continue from there down back in JavaScript

I have a JavaScript code like so:
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
for (var i = 0, di = 1; i >= 0; i += di) {
if (i == myArray.length - 1) { di = -1; }
document.writeln(myArray[i]);
}
I need it to stop right in the middle like 10 and from 10 starts counting down to 0 back.
So far, I've managed to make it work from 0 to 20 and from 20 - 0.
How can I stop it in a middle and start it from there back?
Please help anyone!
Here is an example using a function which accepts the array and the number of items you want to display forwards and backwards:
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
if(myArray.length === 1){
ShowXElementsForwardsAndBackwards(myArray, 1);
}
else if(myArray.length === 0) {
//Do nothing as there are no elements in array and dividing 0 by 2 would be undefined
}
else {
ShowXElementsForwardsAndBackwards(myArray, (myArray.length / 2));
}
function ShowXElementsForwardsAndBackwards(mYarray, numberOfItems){
if (numberOfItems >= mYarray.length) {
throw "More Numbers requested than length of array!";
}
for(let x = 0; x < numberOfItems; x++){
document.writeln(mYarray[x]);
}
for(let y = numberOfItems - 1; y >= 0; y--){
document.writeln(mYarray[y]);
}
}
Just divide your array length by 2
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
for (var i = 0, di = 1; i >= 0; i += di) {
if (i == ((myArray.length / 2) -1 )) { di = -1; }
document.writeln(myArray[i]);
}
Could Array.reverse() help you in this matter?
const array = [0,1,3,4,5,6,7,8,9,10,11,12,13,14,15]
const getArrayOfAmount = (array, amount) => array.filter((item, index) => index < amount)
let arraySection = getArrayOfAmount(array, 10)
let reversed = [...arraySection].reverse()
console.log(arraySection)
console.log(reversed)
And then you can "do stuff" with each array with watever array manipulation you desire.
Couldn’t you just check if you’ve made it halfway and then subtract your current spot from the length?
for(i = 0; i <= myArray.length; i++){
if( Math.round(i/myArray.length) == 1 ){
document.writeln( myArray[ myArray.length - i] );
} else {
document.writeln( myArray[i] );
}
}
Unless I’m missing something?
You could move the checking into the condition block of the for loop.
var myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
for (
var i = 0, l = (myArray.length >> 1) - 1, di = 1;
i === l && (di = -1), i >= 0;
i += di
) {
document.writeln(myArray[i]);
}
If you capture the midpoint ( half the length of the array ), just start working your step in the opposite direction.
const N = 20;
let myArray = [...Array(N).keys()];
let midpoint = Math.round(myArray.length/2)
for ( let i=1, step=1; i; i+=step) {
if (i === midpoint)
step *= -1
document.writeln(myArray[i])
}
To make things clearer, I've:
Started the loop iterator variable (i) at 1; this also meant the array has an unused 0 value at 0 index; in other words, myArray[0]==0 that's never shown
Set the the loop terminating condition to i, which means when i==0 the loop will stop because it is falsy
Renamed the di to step, which is more consistent with other terminology
The midpoint uses a Math.round() to ensure it's the highest integer (midpoint) (e.g., 15/2 == 7.5 but you want it to be 8 )
The midpoint is a variable for performance reasons; calculating the midpoint in the loop body is redundant and less efficient since it only needs to be calculated once
For practical purpose, made sizing the array dynamic using N
Updated to ES6/ES7 -- this is now non-Internet Explorer-friendly [it won't work in IE ;)] primarily due to the use of the spread operator (...) ... but that's easily avoidable

Most efficient method to check for range of numbers within number without duplicates

Given a number n , a minimum number min , a maximum number max , what is the most efficient method to determine
Number n is or is not within range , inclusive of , min - max
Number n does or does not contain duplicate numbers
Efficiency meaning here that the method or set of methods requires the least amount of computational resources and returns either true or false in the least amount of time
Context: Condition at if within a for loop which could require from thousands to hundreds of thousands of iterations to return a result; where milliseconds required to return true or false as to Number check could affect performance
At Profiles panel at DevTools on a collection of 71,3307 items iterated, RegExp below was listed as using 27.2ms of total 1097.3ms to complete loop . At a collection of 836,7628 items iterated RegExp below used 193.5ms within total of 11285.3ms .
Requirement: Most efficient method to return Boolean true or false given above parameters , within the least amount of time.
Note: Solution does not have to be limited to RegExp ; used below as the pattern returned expected results.
Current js utilizing RegExp re , RegExp.protype.test()
var min = 2
, max = 7
, re = new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
, arr = [81, 35, 22, 45, 49];
for (var i = 0; i < arr.length; i++) {
console.log(re.test(arr[i]), i, arr[i])
/*
false 0 81
true 1 35
false 2 22
true 3 45
false 4 49
*/
}
Associative arrays approach:
This has the advantage of being easily understandable.
function checkDigits(min, max, n) {
var digits = Array(10); // Declare the length of the array (the 10 digits) to avoid any further memory allocation
while (n) {
d = (n % 10); // Get last digit
n = n / 10 >>0; // Remove it from our number (the >>0 bit is equivalent to compose(Math.floor, Math.abs))
if (d < min || d > max || digits[d]) // Test if "d" is outside the range or if it has been checked in the "digits" array
return false;
else
digits[d] = true; // Mark the digit as existing
}
}
var min = 2
, max = 7
, arr = [81, 35, 22, 45, 49];
function checkDigits(min, max, n) {
var digits = Array(10); // Declare the length of the array (the 10 digits) to avoid any further memory allocation
while (n) {
d = (n % 10); // Get last digit
n = n / 10 >>0; // Remove it from our number (the >>0 bit is equivalent to compose(Math.floor, Math.abs))
if (d < min || d > max || digits[d]) // Test if "d" is outside the range or if it has been checked in the "digits" array
return false;
else
digits[d] = true; // Mark the digit as existing
}
return true;
}
for (var i = 0; i < arr.length; i++) {
console.log(checkDigits(min, max, arr[i]), i, arr[i])
}
Binary mask approach:
This replaces the Array with an integer that is in effect used as an array of bits. It should be faster.
function checkDigits(min, max, n) {
var digits = 0;
while (n) {
d = (n % 10);
n = n / 10 >>0;
if (d < min || d > max || (digits & (1 << d)))
return false;
else
digits |= 1 << d;
}
return true;
}
function checkDigits(min, max, n) {
var digits = 0;
while (n) {
d = (n % 10);
n = n / 10 >>0;
if (d < min || d > max || (digits & (1 << d)))
return false;
else
digits |= 1 << d;
}
return true;
}
Explanation for binary mask approach:
1 << d creates a bit mask, an integer with the d bit set and all other bits set to 0.
digits |= 1 << d sets the bit marked by our bit mask on the integer digits.
digits & (1 << d) compares the bit marked by our bit mask with digits, the collection of previously marked bits.
See the docs on bitwise operators if you want to understand this in detail.
So, if we were to check 626, our numbers would go like this:
________n_____626_______________
|
d | 6
mask | 0001000000
digits | 0000000000
|
________n_____62________________
|
d | 2
mask | 0000000100
digits | 0001000000
|
________n_____6_________________
|
d | 6
mask | 0001000000
digits | 0001000100
^
bit was already set, return false
Solution 1
test using regex
var min = 2;
var max = 7;
res = "";
arr = [81, 35, 22, 45, 49]
arr.push("");
regex=new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
var result = arr.reduce(function(a, b) {
if (regex.test(a)) {
res = res + a + " is true\n"
} else {
res = res + a + " is false\n"
};
return b
});
console.log(res)
The reduce method is different in a sense that it is like a generator function like in python (produces output on the fly)
Its simply loops through each elements in an array using a callback function. I cannot say how efficient is the reduce function.
Nevertheless consider two elements in the array
81 35
^
take this value take the result
and do something from the previous
element and add it
to the result computed
for this element
further information https://msdn.microsoft.com/en-us/library/ff679975%28v=vs.94%29.aspx
SOlution 2
Using list to store value and their boolean
var min = 2;
var max = 7;
res = [""];
arr = [81, 35, 22, 45, 49]
arr.push("");
regex=new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
var result = arr.reduce(function(a, b) {
if (regex.test(a)) {
res.push([a,true])
} else {
res.push([a,false])
};
return b
});
console.log(res)

Categories

Resources