I am not able to understand this solution properly. I understood the Array declaration part but I am not sure what's going on in the while loop.
function roman(num) {
var decimalValue = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
var romanNumeral = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
var romanized = '';
for (var index = 0; index < decimalValue.length; index++) {
while (decimalValue[index] <= num) {
romanized += romanNumeral[index];
num -= decimalValue[index];
}
}
return romanized;
}
Next time you're stuck on a loop-based problem like this, I would suggest learning about the debugger; command and breakpoints.
Let's use a specific number as an example, say... 2,652. Here's what will happen:
Starting with 1,000 (the first number in decimalValue), check if 2,562 > 1,000.
It is! So, we know that the Roman numeral for 2,652 has at least one M in it. We add M to our output Roman numeral.
We've "accounted for" 1,000 of our number as a numeral, so we remove 1,000 from the number. We now have 1,562.
We jump back up to checking if num > 1,000. It still is. So, we add another M and subtract another 1,000. Now we have 562 of our number "unaccounted for."
This time, when we jump up to the start of our while() loop to test if num > 1,000, we find that it isn't the case! So the loop does not run this time.
This process repeats for all the numbers in decimalValue; all the numbers that have Roman numeral equivalents.
So, we check 900/CM, and find that this number (which is now down to 562) can not be represented as a sum including 900.
Next, we check 500, and find that it can! We add the Roman numeral for 500 to our current romanized string and carry on. We now have MMD and our number is down to 62 "unaccounted for" digits/units/whatever we're counting.
The next number to catch our while() loop is 50, since 62 > 50. We add the L for 50 and bring our number down to 12. Then again on 10, and we add an X. Finally, we match on the last item in decimalValue, 1, twice, and add two Is.
Our final string for this number, 2,652, is MMDXII.
The While loop does a comparison starting from index zero to the last and compares if the value of num passed in is less that the value at index of decimal value array if it is, It will then it appends(concatenate) the ruman numeral at that particular index to the randomize and subtract the equivalent number in decimal(mutate the num variable) from the num which was sent in.
It then checks if num is still greater than the value at that particular index indicating decimal.
taking a walk through with 3002 as example.
First check if index 0 which has 1000 is less than 3002 true
Set randomize to ruman numeral at position index. In this case we have 'M' then subtract decimal at position index from num(3002) we now have num = 2002.
The while loop iterate again and check is 1000 less than 2002? yes it is so it will execute the body of the while loop again.
Append(Concatenate the value at position index(which has not changed yet) to the randomize variable this case index is still zero so we appending 'M' now randomize is 'MM'. Subtract the decimal at position index(0) from num(2002) we now have num = 1002.
Iterate the while loop and check if decimal value at position index(0) of the decimalValue array is less than num(1002) which is true in this case. execute the loop as before.
Append(Concatenate the value at position index(which has not changed yet) to the randomize variable this case index is still zero so we appending 'M' now randomize is 'MMM'. Subtract the decimal at position index(0) from num(1002) we now have num = 2.
Iterate the while loop and check if decimal value at position index(0) of the decimalValue array is less than num(2) which is false in this case. Stop execution of the loop and increment the value of index in the for loop and do the checks again. till you reach the end.
decimalValue[i] represents the same value as romanNumeral[i] for any i. This represents the same data as if the author used a object {4:"IV", 5:"V", ...} except objects to not preserve order. Since the author wants to check larger numbers before smaller numbers, they use this to preserve order and also associate the decimal values with the Roman Numerals.
The loop is confusing because javascript uses + to represent both numerical addition, 2+4==6, and string concatenation, "a"+"b"=="ab".
romanized += romanNumeral[index] means append the string contained in romanNumberal[index] to the end of the string romanized.
num -= decimalValue[index]; means decrease num by the number contained in decimalValue[index]
//start at the big values that have roman number codes, then try smaller values
for (var index = 0; index < decimalValue.length; index++) {
//if the value we are testing is less or equal to num
// (actually loop but for reasons explained below)
while (decimalValue[index] <= num) {
//append the string in romanNumberal to
//the end of the string in the variable romanized
romanized += romanNumeral[index];
//from the number num, substract the
//value we just added to romanized
num -= decimalValue[index];
//what about a case like 3, which needs
//repeated letters in that case "III".
//That is why this is a while statement and not an if.
//the while loop keeps processing
//those cases until we have enough repeated letters.
}
}
When we need more than one of the same the same letter, then decimalvalue[index] will still be less than or equal to num.
This is because when we reach decimalvalue[index], we know that num < decimalvalue[index-1] (except for the start), because the while loop prevents index from increasing until that is true.
Often the loop only runs once. For example, going from decimalvalue[index] == 10 to decimalvalue[index] == 9 loop only runs once at most because num < 10 and 10-9==1 which is less than 9. So then, the while loop acts as just an if statement.
The loop only loops for values where duplicate letters are valid in roman numerals, because that is were the drop in value between decimalvalue[i-1] and decimal[i] is great enough. More precisely those are the only times when decimalvalue[i-1]/decimalvalue[i] >= 2 (that is 2 or more of a value in decimalvalue[i] fits in the previous decimalvalue)
if you know the division algorithm from math this is kinda like that.
Found this codepen on google. The code is pretty straightforward, I hope it will help.
Roman Numeral Converter in Javascript
function convert(num){
num = parseInt(num);
var result = '',
ref = ['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'],
xis = [1000,900,500,400,100,90,50,40,10,9,5,4,1];
if (num >= 4000) {
num += ''; // need to convert to string for .substring()
result = '<span style="border-top: 1px solid; margin-top: 2px; display: inline-block; padding-top: 0px;">'+convert(num.substring(0,num.length-3))+'</span>';
num = num.substring(num.length-3);
}
for (x = 0; x < ref.length; x++){
while(num >= xis[x]){
result += ref[x];
num -= xis[x];
}
}
return result;
}
$('input').on('keyup keydown change',function(e){
var $this = $(this),
val = $this.val();
if (val.length == 0) return $('#result').html('');
if (isNaN(val)) return $('#result').html('Invalid input');
if (e.type == 'keydown'){
if (e.keyCode === 38) $this.val(++val);
if (e.keyCode === 40) $this.val(--val);
}
if (val < 1) return $('#result').html('Number is too small');
$('#result').html(convert(val));
})
Related
Trying to solve this Codewars challenge.
You have a positive number n consisting of digits. You can do at most one operation: Choosing the index of a digit in the number, remove this digit at that index and insert it back to another or at the same place in the number in order to find the smallest number you can get.
Task: Return an array or a tuple or a string depending on the language (see "Sample Tests") with:
1) the smallest number you got
2) the index i of the digit d you took, i as small as possible
3) the index j (as small as possible) where you insert this digit d to have the smallest number.
Example:
smallest(261235) --> [126235, 2, 0] or (126235, 2, 0) or "126235, 2, 0"
Other examples:
209917, [29917, 0, 1]
285365, [238565, 3, 1]
269045, [26945, 3, 0]
296837, [239687, 4, 1]
So, in order to get the smallest number possible, we will want to remove the smallest digit from the number and place it at the front of the number, correct?
function smallest (n) {
//turn n into an array
let array = String(n).split("").map(Number);
let smallest = Math.min(...array);
//find index of smallest in original array
let index = array.indexOf(smallest);
//remove smallest from original array, move it to front
array.splice(index, 1);
array.unshift(smallest);
let newNumber = Number(array.join(""));
//return array of new number, index of where the smallest was,
//and index of where the smallest is now
return ([newNumber, index, 0]);
}
console.log(smallest(239687));
My answer is returning the correct number, but, about half the time, it is not returning the correct index i and index j.
EDIT: Latest attempt:
function smallest (n) {
let array = Array.from(String(n)).map(Number);
let original = Array.from(String(n)).map(Number);
let sorted = Array.from(String(n)).map(Number).sort((a, b) => a - b);
let swapValueOne = [];
let swapValueTwo = [];
for (let i = 0; i < array.length; i++) {
if (array[i] !== sorted[i]) {
swapValueOne.push(sorted[i]);
swapValueTwo.push(original[i]);
break;
}
}
swapValueOne = Number(swapValueOne);
swapValueTwo = Number(swapValueTwo);
let indexOne = original.indexOf(swapValueOne);
let indexTwo = original.indexOf(swapValueTwo);
//remove swapValue
array.splice(indexOne, 1);
//insert swapValue
array.splice(indexTwo, 0, swapValueOne);
return ([Number(array.join("")), indexOne, array.indexOf(swapValueOne)]);
}
console.log(smallest(296837));
^ Sometimes it gives the correct number with the correct swap indices, and sometimes both the number and the swap indices are wrong.
Putting the smallest element in the front (let's call it a "greedy" solution) is non-optimal. Consider the case where n = 296837, as in your last test case. Your code returns [296837, 0, 0] because it finds that 2 is the smallest digit and it moves it to the front (does nothing, essentially). As your example illustrates, there's a better approach: [239687, 4, 1], that is, move 3 to the first index in the array.
You'll need to reformulate your strategy to be non-greedy to find a global optimum.
If you're still stuck, you can try the following:
Numbers can't contain that many digits--why not try every possible swap?
Here's a small idea that might help.
If you have a number like:
239687
The smallest number you can make with this is the sorted digits:
236789
In the original number, the 2 and the 3 are already in the correct position. If you start from the left of the number and the sorted number, the first difference you find is the number that needs to be swapped. It needs to be swapped with the corresponding number in the sorted list:
orig 2 3 9 6 8 7 -- 6 needs to go before 9
| | x
sorted 2 3 6 7 8 9
Above the next sorted digit is 6, but the original has 9. You need to insert 6 before 9.
For an algorithm you can sort your digits and find the index of the first difference (starting from the left). This is one of your return values (2 in the example). Now find the index of sorted[2] (ie. 6) in the original (index 3). Insert the value in you original array and you're done.
The approach of finding the first not sorted element doesnt solve correctly all the cases for example if the number is 300200, the first not sorted number is the 3 and if you put a 0 in that place, depending what 0 you move you got:
(0)30020
(0)30020
(0)30200
(0)30200
All of the answers are wrong because what you have to do is to put the 3 at the end of the number to get
(000)2003
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.
I am trying to count TRAILING zeros from a recursive manner. Basically I split the final recursive result and then created a var counter that will count all the zeros.
function countingZeros(n) {
if (n < 0) {
// Termination condition to prevent infinite recursion
return;
}
// Base case
if (n === 0) {
return 1;
}
// Recursive case
let final = n * countingZeros(n -1);
let counter = 0;
String(final).split('').forEach(function(item){
item === 0 ? counter++ : counter;
});
return counter;
}
countingZeros(12) // => suppose to output 2 since there are 2 trailing zeros from 479001600 but got 0
countingZeros(6) // => suppose to get 1 since 720 is the final result.
I am expecting to get 2 in return as the counter must return but instead I got 0. Any idea what am I missing on my function? How should I fix it?
I think you're working too hard. First of all, in response to a comment, you don't actually need to calculate the factorial, since all you really need is to count factors of 5 and of 2. And since there are many more factors of 2, your real answer is just counting factors of 5. But each factor of 5 must be a factor of one of {1, 2, 3, ... n}, so we just have to add up the highest powers of five that evenly divide into each of {1, 2, 3, ... n}.
We can do that with some simple recursion:
const fiveFactors = (n, acc = 0) => (n % 5 == 0)
? fiveFactors(n / 5, acc + 1)
: acc
const factZeros = (n, acc = 0) => (n > 0)
? factZeros(n - 1, acc + fiveFactors(n))
: acc
factZeros(1000) //=> 249
Note that both functions are eligible for tail-call optimization.
Also, although this does involve a double recursion, it's not really ill-performant. Four out of five times, the internal recursion stops on the first call, and of the remainder, four out of five stop on the second call, and so on.
You are trying to count the number of zeroes using string functions(i will assume, you forgot to include the factorial method. Correct flow could have been- you first pass the input to a factorial method and pass output from factorial method to countingZeros method). Anyways as stated already in other answer, you don't really need to calculate the factorial product to count the trailing zeroes.
Here a sample to count the number of trailing zeroes in n!
temp = 5;
zeroes = 0;
//counting the sum of multiples of 5,5^2,5^3....present in n!
while(n>=temp){
fives = n/temp;
zeroes = zeroes + fives;
temp = temp*5;
}
printf("%d",zeroes);
Note that each multiple of 5 in the factorial product will contribute 1 to the number of trailing zeros. On top of this, each multiple of 25 will contribute an additional 1 to the number of trailing zeros. Then, each multiple of 125 will contribute another 1 to the number of trailing zeros, and so on.
Here's a great link to understand the concept behind this:
https://brilliant.org/wiki/trailing-number-of-zeros/
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 think the title needs some explaining. I wan't to make my program break up a number into smaller bits.
For example, it would break 756 into 700, 50 and 6. 9123 would be 9000, 100, 20 and 3. Is there any way I can do this for any reasonably sized number?
Working Example
Here is a function that can do it:
function breakNumbers(num){
var nums = num.toString().split('');
var len = nums.length;
var answer = nums.map(function(n, i) {
return n + (Array(len - i - 1).fill(0)).join('');
});
return answer.map(Number).filter(function(n) {return n !== 0;});
}
function breakup(number) {
var digits = String(number).split('')
return digits.map(function(digit, i) {
return Number(digit.concat("0".repeat(digits.length - i - 1)))
}).filter(function(n) { return n !== 0 })
}
So first, we want to cast the number to a string, so we pass it into the String primitive like so: String(number)
Thus, calling the split method on the array and passing in an empty string (which tells it to split for every character) results in an array of the digits, i.e. ["7", "5", "6"]
We can leave them as strings for now because it makes the next part a little easier. Using the map function, you can pass a function which should be called on each element in the array. Besides the first argument to this function, there's an optional second argument which is the index of the item in the array. This will turn useful in our case, since where a number is in the array indicates what place it is.
Check it out, the value returned by the function passed to map takes the current number string and concats another string onto it, which is a number of repeated "0"s. That number is determined by looking at the parent array's length and subtracting it from the index of the current item being looped on, minus one. This is because arrays are 0-indexed in JavaScript--if we just subtracted digits.length from the i (index) for the first iteration, the values would be 3 and 0 respectively, so you'd end up with 7000 for the first value if you passed in 756. Note also that in our return statement inside the map function, we wrap it back in a Number primitive to cast it back from a string.
Also, you didn't mention this, but I assume you'd rather not have numbers which equal 0 in your example. By calling filter on the final array before its returned, we can effectively make sure that only items which are not equal to 0 are returned. Thus, if you call breakup(756) you'll recieve [700, 50, 6], but breakup(706) will give you [700, 6] instead.
Instead of using split() to break out digits, I used a regex to tokenize the number string. This way, we can easily handle any trailing decimals by treating a digit followed by a decimal point and any further digits as a single token. This also makes it possible to handle digits as part of a larger string.
function splitNumber( number ) {
var parts = [];
var re = /(\d(?:\.\d*)?)/g;
while(next_part = re.exec(number)) {
// adjust place value
parts.forEach( function(element, index) {
parts[index] = 10 * element;
} );
parts.push( next_part[0] );
}
return parts.map(Number).filter(function(n) {return n !== 0});
}