Greetings Stack Overflow!
First off, this is my first question!
I am trying to solve the selfDividingNumbers algorithm and I ran into this interesting problem. This function is supposed to take a range of numbers to check if they are self dividing.
Self Dividing example:
128 is a self-dividing number because
128 % 1 == 0, 128 % 2 == 0, and 128 % 8 == 0.
My attempt with Javascript.
/*
selfDividingNumbers( 1, 22 );
*/
var selfDividingNumbers = function(left, right) {
var output = [];
while(left <= right){
// convert number into an array of strings, size 1
var leftString = left.toString().split();
// initialize digit iterator
var currentDigit = leftString[0];
for(var i = 0; i < leftString.length; i++){
currentDigit = parseInt(leftString[i])
console.log( left % currentDigit );
}
// increment lower bound
left++;
}
return output
};
When comparing the current lower bound to the current digit of the lower bound, left % currentDigit it always produces zero! I figure this is probably a type error but I am unsure of why and would love for someone to point out why!
Would also like to see any other ideas to avoid this problem!
I figured this was a good chance to get a better handle on Javascript considering I am clueless as to why my program is producing this output. Any help would be appreciated! :)
Thanks Stack Overflow!
Calling split() isn't buying you anything. Remove it and you'll get the results you expect. You still have to write the code to populate output though.
The answer by #Joseph may fix your current code, but I think there is a potentially easier way to go about doing this. Consider the following script:
var start = 128;
var num = start;
var sd = true;
while (num > 0) {
var last = num % 10;
if (start % last != 0) {
sd = false;
break;
}
num = Math.floor(num / 10);
}
if (sd) {
print("Is self dividing");
}
else {
print("Is NOT self dividing");
}
Demo
To test each digit in the number for its ability to cleanly divide the original number, you can simply use a loop. In each iteration, check num % 10 to get the current digit, and then divide the number by ten. If we never see a digit which can not divide evenly, then the number is not self dividing, otherwise it is.
So the string split method takes the string and returns an array of string parts. The method expects a parameter, however, the dividing element. If no dividing element is provided, the method will return only one part, the string itself. In your case, what you probably intended was to split the string into individual characters, which would mean the divider would be the empty string:
var leftString = left.toString().split('');
Since you are already familiar with console.log, note that you could also use it to debug your program. If you are confused about the output of left % currentDigit, one thing you could try is logging the variables just before the call,
console.log(typeof left, left, typeof currentDigit, currentDigit)
which might give you ideas about where to look next.
Related
Problem statement: I'm trying to get string > binary without using the inbuilt method in javascript.
This is a piece of program where a string input (like "ABC") is accepted, then it is translated to an array of equivalent code value ([65,66,67]).
Function binary() will change a number to binary. But I'm unable to join them together to loop through all the contents. Please help. (I'm a noob, please forgive my bad code and bad explanation)
var temp3 = [65,66,67];
var temp2 = [];
var r;
for(i=0;i<temp3.length;i++) {
var r = temp3[i];
temp2.push(binary(r));
}
function binary(r) {
if (r === 0) return;
temp2.unshift(r % 2);
binary(Math.floor(r / 2));
return temp2;
}
console.log(temp2);
I think this is a cleaner version of this function. It should work for any non-negative integers, and would be easy enough to extend to the negatives. If we have a single binary digit (0 or 1) and hence are less than 2, we just return the number converted to a string. Otherwise we call recursively on the floor of half the number (as yours does) and append the final digit.
const binary = (n) =>
n < 2
? String (n)
: binary (Math.floor (n / 2)) + (n % 2)
console.log (binary(22)) //=> '10110'
console.log ([65, 66, 67] .map (binary)) //=> ['1000001', '1000010', '1000011']
In your function you have this code
var r = temp3[i];
I don't see any temp3 variable anywhere in your code above so I'd imagine that could be causing some issues.
I am trying to solve the problem described here with JavaScript...
https://www.hackerrank.com/challenges/ctci-making-anagrams
I have to output the number of letters that would need to be removed from two strings in order for there to only be matching letters (compare the two strings for matching letters and total the letters that don't match)
for example...
string a = cbe
string b = abc
the only matching letter is between both strings is the two c's so I would be removing 4 letters (beab).
My code works, but it seems to keep timing out. If I download the individual test case instances, I seem to fail when variables a and b are set to large strings. If I test these individually, I seem to get the right output but i still also get the message "Terminated due to timeout".
I'm thinking it might be obvious to someone why my code timesout. I'm not sure it's the most elegant way of solving the problem but I'd love to get it working. Any help would be much appreciated...
function main() {
var a = readLine();
var b = readLine();
var arraya = a.split('');
var arrayb = b.split('');
var arraylengths = arraya.length + arrayb.length;
//console.log(arraylengths);
if (arraya.length <= arrayb.length) {
var shortestarray = arraya;
var longestarray = arrayb;
} else {
var shortestarray = arrayb;
var longestarray = arraya;
}
var subtract = 0;
for (x = 0; x < shortestarray.length; x++) {
var theletter = shortestarray[x];
var thenumber = x;
if (longestarray.indexOf(theletter, 0) > -1) {
var index = longestarray.indexOf(theletter, 0);
longestarray.splice(index, 1);
subtract = subtract + 2;
}
}
var total = arraylengths - subtract;
console.log(total);
}
Your algorithm is good. It's straight forward and easy to understand.
There are certain things you can do to improve the performance of your code.
You don't have to calculate the indexOf operation twice. you can reduce it to one.
the splice operation is the costliest operation because the JS engine has to delete the element from an array and reassign the indexes of all the elements.
A point to be noted here is that the JS engine does an extra step of correcting the index of the array, which is not required for your purpose. So you can safely remove longestarray.splice(index, 1); and replace it with delete longestarray[index]
Here is a snippet which will increase your performance of the code without changing your logic
for (var x = 0; x < shortestarray.length; x++) {
var theletter = shortestarray[x];
var thenumber = longestarray.indexOf(theletter, 0); // <-- check only once
if (thenumber > -1) {
var index = thenumber;
delete longestarray[index]; // <-- less costlier than splice
subtract = subtract + 2;
}
}
Note: I am not suggesting you to use delete for all the cases. It's useful here because you are not going to do much with the array elements after the element is deleted.
All the best. Happy Coding
I would suggest you hashing. make the characters of string key and its numbers of occurrences value. Do the same for both strings. After that take string 1 and match the count of its every character with the count of same character in string then calculate the difference in the number of occurrences of the same character and delete that character till the difference becomes 0 and count that how many times you performed delete operation.
ALGORITHM:
step 1: Let arr1[255]= an integer array for storing the count of string1[i]
and initialized to zero
ex: string1[i]='a', then arr1[97]=1, because ASCII value of a is 97
and its count is 1. so we made hash table for arr1 where key is
ASCII value of character and value is its no of occurrences.
step 2: Now declare an another array of same type and same size for string 2
step 3: For i=0 to length(string1):
do arr1[string1[i]]++;
step 4: For i=0 to length(string2):
do arr2[string2[i]]++;
step 5: Declare an boolean char_status[255] array to check if the
character is visited or not during traversing and initialize it to
false
step 6: set count=0;
step 7: For i=0 to length(string1):
if(char_status[string1[i]]==false):
count=count+abs(arr1[string1[i]]-arr2[string1[i]])
char_status[string1[i]]=true
step 8: For i=0 to length(string2):
if(char_status[string2[i]]==false):
count=count+abs(arr1[string2[i]]-arr2[string2[i]])
char_status[string2[i]]=true
step 9: print count
I have applied this algo just now and passed all test cases. You may improve this algo more if you have time.
I'm totally not a Math whiz kid here, but have put together a function with the great help of StackOverflow (and a lot of trial and error) that generates a random serial number from a Formula, group of Letters/Numbers, and array (so as to not duplicate values).
So, my current formula is as follows:
$.extend({
generateSerial: function(formula, chrs, checks) {
var formula = formula && formula != "" ? formula : 'XXX-XXX-XXX-XXX-XXX', // Default Formula to use, should change to what's most commonly used!
chrs = chrs && chrs != "" ? chrs : "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", // Default characters to randomize, if not defined!
len = (formula.match(/X/g) || []).length,
indices = [],
rand;
// Get all "-" char indexes
for(var i=0; i < formula.length; i++) {
if (formula[i] === "-") indices.push(i);
}
do {
rand = Array(len).join().split(',').map(function() {
return chrs.charAt(Math.floor(Math.random() * chrs.length));
}).join('');
// Rebuild string!
if (indices && indices.length > 0)
{
for(var x=0; x < indices.length; x++)
rand = rand.insert(indices[x], '-');
}
} while (checks && $.inArray(rand, checks) !== -1);
return rand;
}
});
Ok, so, what I need to be able to do is to find total possible values and make sure that it is possible to generate a unique serial number before actually doing so.
For example:
var num = $.generateSerial('XX', 'AB', new Array('AB', 'BA', 'AA', 'BB'));
This will cause the code to do an infinite loop, since there are no more possibilties here, other than the ones being excluded from the extension. So this will cause browser to crash. What I need to be able to do here is to be able to get the number of possible unique values here and if it is greater than 0, continue, otherwise, don't continue, maybe an alert for an error would be fine.
Also, keep in mind, could also do this in a loop so as to not repeat serials already generated:
var currSerials = [];
for (var x = 0; x < 5; x++)
{
var output = $.generateSerial('XXX-XXX-XXX', '0123456789', currSerials);
currSerials.push(output);
}
But the important thing here, is how to get total possible unique values from within the generateSerial function itself? We have the length, characters, and exclusions array also in here (checks). This would seem more like a math question, and I'm not expert in Math. Could use some help here.
Thanks guys :)
Here is a jsFiddle of it working nicely because there are more possible choices than 16: http://jsfiddle.net/qpw66bwb/1/
And here is a jsFiddle of the problem I am facing: Just click the "Generate Serials" button to see the problem (it continuously loops, never finishes), it wants to create 16 serials, but 16 possible choices are not even possible with 2 characters and only using A and B characters: http://jsfiddle.net/qpw66bwb/2/
I need to catch the loop here and exit out of it, if it is not able to generate a random number somehow. But how?
The number of possible serials is len * chrs.length, assuming all the characters in chrs are different. The serial contains len characters to fill in randomly, and chrs.length is the number of possible characters in each position of that.
var number = 342345820139586830203845861938475676
var output = []
var sum = 0;
while (number) {
output.push(number % 10);
number = Math.floor(number/10);
}
output = output.reverse();
function addTerms () {
for (i = 0; i < output.length; i=i+2) {
var term = Math.pow(output[i], output[i+1]);
sum += term;
}
return sum;
}
document.write(output);
document.write("<br>");
document.write(addTerms());
I am trying to take that large number and split it into its digits. Then, find the sum of the the first digit raised to the power of the 2nd, 3rd digit raiseed to the 4th, 5th raised to the 6th and so on. for some reason, my array is returning weird digits, causing my sum to be off. the correct answer is 2517052. Thanks
You're running into precision issues within JavaScript. Just evaluate the current value of number before you start doing anything, and the results may surprise you:
>>> var number = 342345820139586830203845861938475676; number;
3.423458201395868e+35
See also: What is JavaScript's highest integer value that a Number can go to without losing precision?
To resolve your issue, I'd store your input number as an array (or maybe even a string), then pull the digits off of that.
This will solve your calculation with the expected result of 2517052:
var number = "342345820139586830203845861938475676";
var sum = 0;
for(var i=0; i<number.length; i=i+2){
sum += Math.pow(number.charAt(i), number.charAt(i+1));
}
sum;
JavaScript stores numbers in floating point format (commonly double). double can store precisely only 15 digits.
You can use string to store this large number.
As mentioned, this is a problem with numeric precision. It applies to all programming languages that use native numeric formats. Your problem works fine if you use a string instead
var number = '342345820139586830203845861938475676'
var digits = number.split('')
var total = 0
while (digits.length > 1) {
var [n, power] = digits.splice(0, 2)
total += Math.pow(n, power)
}
(the result is 2517052, byt the way!)
Cast the number as a string and then iterate through it doing your math.
var number = "342345820139586830203845861938475676";//number definition
var X = 0;//some iterator
var numberAtX = 0 + number.charAt(X);//number access
The greatest integer supported by Javascript is 9007199254740992. So that only your output is weird.
For Reference go through the link http://ecma262-5.com/ELS5_HTML.htm#Section_8.5
[edit] adjusted the answer based on Borodins comment.
Mmm, I think the result should be 2517052. I'd say this does the same:
var numbers = '342345820139586830203845861938475676'.split('')
,num = numbers.splice(0,2)
,result = Math.pow(num[0],num[1]);
while ( (num = numbers.splice(0,2)) && num.length ){
result += Math.pow(num[0],num[1]);
}
console.log(result); //=> 2517052
The array methods map and reduce are supported in modern browsers,
and could be worth defining in older browsers. This is a good opportunity,
if you haven't used them before.
If you are going to make an array of a string anyway,
match pairs of digits instead of splitting to single digits.
This example takes numbers or strings.
function sumPower(s){
return String(s).match(/\d{2}/g).map(function(itm){
return Math.pow(itm.charAt(0), itm.charAt(1));
}).reduce(function(a, b){
return a+b;
});
}
sumPower('342345820139586830203845861938475676');
alert(sumPower(s))
/*
returned value:(Number)
2517052
*/
While playing around with random numbers in JavaScript I discovered a surprising bug, presumably in the V8 JavaScript engine in Google Chrome. Consider:
// Generate a random number [1,5].
var rand5 = function() {
return parseInt(Math.random() * 5) + 1;
};
// Return a sample distribution over MAX times.
var testRand5 = function(dist, max) {
if (!dist) { dist = {}; }
if (!max) { max = 5000000; }
for (var i=0; i<max; i++) {
var r = rand5();
dist[r] = (dist[r] || 0) + 1;
}
return dist;
};
Now when I run testRand5() I get the following results (of course, differing slightly with each run, you might need to set "max" to a higher value to reveal the bug):
var d = testRand5();
d = {
1: 1002797,
2: 998803,
3: 999541,
4: 1000851,
5: 998007,
10: 1 // XXX: Math.random() returned 4.5?!
}
Interestingly, I see comparable results in node.js, leading me to believe it's not specific to Chrome. Sometimes there are different or multiple mystery values (7, 9, etc).
Can anyone explain why I might be getting the results I see? I'm guessing it has something to do with using parseInt (instead of Math.floor()) but I'm still not sure why it could happen.
The edge case occurs when you happen to generate a very small number, expressed with an exponent, like this for example 9.546056389808655e-8.
Combined with parseInt, which interprets the argument as a string, hell breaks loose. And as suggested before me, it can be solved using Math.floor.
Try it yourself with this piece of code:
var test = 9.546056389808655e-8;
console.log(test); // prints 9.546056389808655e-8
console.log(parseInt(test)); // prints 9 - oh noes!
console.log(Math.floor(test)) // prints 0 - this is better
Of course, it's a parseInt() gotcha. It converts its argument to a string first, and that can force scientific notation which will cause parseInt to do something like this:
var x = 0.000000004;
(x).toString(); // => "4e-9"
parseInt(x); // => 4
Silly me...
I would suggest changing your random number function to this:
var rand5 = function() {
return(Math.floor(Math.random() * 5) + 1);
};
This will reliably generate an integer value between 1 and 5 inclusive.
You can see your test function in action here: http://jsfiddle.net/jfriend00/FCzjF/.
In this case, parseInt isn't the best choice because it's going to convert your float to a string which can be a number of different formats (including scientific notation) and then try to parse an integer out of it. Much better to just operate on the float directly with Math.floor().