Find The Smallest - Codewars Challenge - Javascript - javascript

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

Related

Given a non-empty array of digits representing a non-negative integer, increment one to the integer (javascript)

Was wondering if someone could explain the code solution to this problem. It's making no sense to me:
Given a non-empty array of digits representing a non-negative integer, increment one to the integer.
The digits are stored such that the most significant digit is at the head of the list, and each element in the array contains a single digit.
You may assume the integer does not contain any leading zero, except the number 0 itself.
The solution is as follows :
var plusOne = function(digits) {
let carry = true
for (let i = digits.length - 1; i >= 0; i -= 1) {
if (digits[i] === 9 && carry) {
digits[i] = 0;
if (i === 0) {
digits.unshift(1);
break;
}
} else if (carry) {
digits[i] += 1;
carry = false;
}
}
return digits;
};
I have a few questions about this solution :
what is the purpose of the variable carry?
why is digits[i] set to 0?
why is there an if statement checking for (i===0)? And in turn, why is there a 1 added afterwards?
Any guidance would be appreciated, thanks!!
You have an array of integers where every element in the array is represents a digit of a number. Say you are given 456, then at index 0 you have 4, at index 1 you have 5 and at index 2 you have 6.
Now, the problem asks you to add 1 to the given number.
Here carry is mathematical carry that is used when you have to add two digits whose sum is greater than 10. By default we have carry as true because you are adding 1 to the number anyway. First you iterate(reverse) through the given digits and look for digits that are equal to 9 (carry being true), then change the current digit to zero and put 1 in the front. If carry is true and and the digit is not 9 then simply add 1 to the digit.
examples :
plusOne([4,9,7])
(3) [4, 9, 8]
here number 497 is given, and you just add 1 to the last digit.
plusOne([1,4,9])
(3) [1, 5, 0]
here we see that the last digit is 9, so first we change it to zero then we add 1 to the second last digit.
plusOne([9,9,9])
(4) [1, 0, 0, 0]
here we see that all the digit are 9, we change all digits to zero and add 1 in the beginning (this is where unshift 1 is used)

JavaScript Roman Numeral Converter

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));
})

Counting zeros in a recursive manner

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/

Find number of pairs with difference larger than or equal to given number

I have a array/dict(HashMap) of positive integers.
I need to find the number of pairs that have a absolute difference greater or equal to a given number, K.
import random
import time
#given number
k = 4
# List of 2,00,000 random numbers in range 0-1000
strength = [random.randrange(0,1000) for x in range(200000)]
strength.sort()
# start clock
start1 = time.clock()
n = len(strength)
# count keeps track of number of pairs found
count = 0
for x in range(n):
for y in range(x,n):
if abs(strength[x] - strength[y]) >= k:
# if found, all number from this point to the end will satisfy
count += n-y
# So no need to go to the end
break
end1 = time.clock()
print(count)
print(end1-start1)
All the answers I find are for pairs less than or equal to a given number.
I need to find the number of pairs that have a absolute difference greater or equal to a given number, K.
Note that the total number of pairs is n * (n - 1) / 2, so if you can find the number of pairs with difference less than K, the number of pairs with difference greater than K is just n * (n - 1) / 2 - num_pairs_with_diff_less_than_K
The solution you provide is also correct (and well documented). If your question is how to adapt it to your case, then all you need to do is to use values of your HashMap (sorted) instead of the strength array.
You can get the 2 item combinations of the array and then filter / reduce them according to the difference.
One might do the job in JavaScript as follows;
Array.prototype.combinations = function(n){
return this.reduce((p,c,i,a) => p.concat(n > 1 ? a.slice(i+1).combinations(n-1).map(e => (e.push(c),e))
: [[c]]),[]);
};
function getAcordingToDiff(a,d){
return a.combinations(2)
.reduce((p,c) => Math.abs(c[0]-c[1]) >= d ? (p.push(c),p) : p ,[]);
}
var arr = Array(30).fill().map((_,i) => i+1); // array from [1,...,30]
console.log(JSON.stringify(arr))
console.log(JSON.stringify(getAcordingToDiff(arr,25))); // diff >= 25
Explanation:
So in the heart of the above code obviously lies the Array.prototype.combinations function. For those who are not familiar with JS, this is just an ordinary function that we define under the Array object's prototype (so that now every array has access to this function like arr.combinations(n)) But let's use a more expressive language and refactor the above combinations array method into a generic function.
function combinations(a,n){
var sa;
return a.reduce(function(p,c,i,a){
if (n > 1) sa = combinations(a.slice(i+1), n-1).map(e => (e.push(c),e));
else sa = [[c]];
return p.concat(sa);
},[]);
}
So as you will notice combinations(a,n) is a recursive function which takes an array a and items count n. It works on the basis of keeping the first item of the input array and recursively invoking itself with one item shorter array, combinations(a.slice(i+1), n-1), and with one less items count up until n decrements to 1 in which case it starts it's return cycle with whatever remains from the input array and each item is wrapped in an array, sa = [[c]].
So on the return cycle of the recursive calls we take the resulting array and push the kept first element (remember -> It works on the basis of keeping the first item of the input array) into each item of the returned array (remember -> ...and each item is wrapped in an array, sa = [[c]]).
So that's it... You should be able to figure out yourself the details.
However in our application we are given an array of numbers and requested to obtain only the 2 item combinations with a certain difference. In this particular case we don't need to calculate all combinations and then filter them. We can do this on the way constructing our combinations. As the required difference value d gets bigger this will bring in a huge gain over filtering afterwards method, since now as d gets bigger we are eliminating more and more of the two item combinations, even before we generate them. And... let's hard-wire our code to work with 2 items only and merge everything in a single function. The performance results are below;
function getCombosWithDiff(a, d, n = 2){
var sa;
return a.reduce(function(p,c,i,a){
if (n > 1) sa = getCombosWithDiff(a.slice(i+1), d, n-1).reduce((r,e) => Math.abs(e[0]-c) > d ? (e.push(c),r.push(e),r)
: r, []);
else sa = [[c]];
return p.concat(sa);
},[]);
}
var arr = Array(100).fill().map((_,i) => i+1);
result = getCombosWithDiff(arr,89);
console.log(JSON.stringify(arr));
console.log(JSON.stringify(result));
So that's it. I have tried the above code to list the 2 items combinations each with diff greater than 10 from an array of 1000 items. It takes like 5000 msecs in Chrome and 14000 msecs in FF. However as mentioned above, the more the diff value d gets bigger, the shorter it takes. e.g same array with diff 900 would resolve in just 1100msecs with Chrome and in 4000msecs with FF.
You can test and play here
Create a 1001-element array A of integers initialized to zeroes. Generate your random integers, and increment the appropriate index by 1 for each such integer. With some math, you could do this without generating 2,000,000 random integers, but it's not worth the complexity.
Create a second 1001-element integer B s.t. B[i] = A[0] + ... + A[i]
Answer is sum from i=0 to 1000-k of B[i] * (2,000,000 - B[i+k-1])

Decomposing a value into results of powers of two

Is it possible to get the integers that, being results of powers of two, forms a value?
Example:
129 resolves [1, 128]
77 resolves [1, 4, 8, 64]
I already thought about using Math.log and doing also a foreach with a bitwise comparator. Is any other more beautiful solution?
The easiest way is to use a single bit value, starting with 1 and shift that bit 'left' until its value is greater than the value to check, comparing each bit step bitwise with the value. The bits that are set can be stored in an array.
function GetBits(value) {
var b = 1;
var res = [];
while (b <= value) {
if (b & value) res.push(b);
b <<= 1;
}
return res;
}
console.log(GetBits(129));
console.log(GetBits(77));
console.log(GetBits(255));
Since shifting the bit can be seen as a power of 2, you can push the current bit value directly into the result array.
Example
You can adapt solutions from other languages to javascript. In this SO question you'll find some ways of solving the problem using Java (you can choose the one you find more elegant).
decomposing a value into powers of two
I adapted one of those answers to javascript and come up with this code:
var powers = [], power = 0, n = 129;// Gives [1,128] as output.
while (n != 0) {
if ((n & 1) != 0) {
powers.push(1 << power);
}
++power;
n >>>= 1;
}
console.log(powers);
Fiddle
Find the largest power of two contained in the number.
Subtract from the original number and Add it to list.
Decrement the exponent and check if new 2's power is less than the number.
If less then subtract it from the original number and add it to list.
Otherwise go to step 3.
Exit when your number comes to 0.
I am thinking of creating a list of all power of 2 numbers <= your number, then use an addition- subtraction algorithm to find out the group of correct numbers.
For example number 77:
the group of factors is { 1,2,4,8,16,32,64} [ 64 is the greatest power of 2 less than or equal 77]
An algorithm that continuously subtract the greatest number less than or equal to your number from the group you just created, until you get zero.
77-64 = 13 ==> [64]
13-8 = 7 ==> [8]
7-4 = 3 ==> [4]
3-2 = 1 ==> [2]
1-1 = 0 ==> [1]
Hope you understand my algorithm, pardo my bad english.
function getBits(val, factor) {
factor = factor || 1;
if(val) {
return (val % 2 ? [factor] : []).concat(getBits(val>>1, factor*2))
}
return [];
}
alert(getBits(77));

Categories