Electronic shop hackerRank challenge in Javascript - javascript

Hi I did not pass the all the tests, only 9/16. so I want to know what is the problem in my code
problem link:https://www.hackerrank.com/challenges/electronics-shop/problem
function getMoneySpent(keyboards, drives, b) {
let arr = [];
let lenOfArr1 = keyboards.length;
let lenOfArr2 = drives.length;
let j = drives.length;
arr = keyboards.slice(0);
for (let number of drives) {
arr.push(number);
}
return (challenge(arr, lenOfArr1, b));
}
function challenge(arr, lenOfArr1, m) {
let result = [];
let j = lenOfArr1;
for (let i = 0; i < lenOfArr1; i++) {
if (arr[i] >= m || arr[j] >= m) return -1;
if (arr[i] + arr[j] < m) {
result.push(arr[i] + arr[j]);
}
i--;
j++;
if (j == arr.length) {
i++;
j = lenOfArr1;
}
}
if (result.length == 0) return -1;
return result.sort()[result.length - 1];
}

From the given constraints in the problem statement, you don't need such a complex solution.
Here is the Algorithm:
Initialize a variable maxValue to have value as -1.
Start two for loops over drives and keyboards and take all combinations and sum the value of each drive with each keyboard.
Inside the for loops, check if the sum of drive + keyboard and it should be less than or equal to the money Monica has and keep track of the maximum value you get from any combination in maxValue.
After the code computation, return maxValue.
Code:-
function getMoneySpent(keyboards, drives, b) {
let maxValue = -1;
for (let drive of drives) {
for(let keyboard of keyboards) {
let cost = drive + keyboard;
if(cost > maxValue && cost <= b) {
maxValue = cost;
}
}
}
return maxValue;
}
Overall Time complexity - O(n^2).
Hope this helps!

The following line causes your code to return -1 when there might be a solution:
if (arr[i] >= m || arr[j] >= m) return -1;
Even though one price may be above budget, you need to consider that there might be cheaper items available. You might even already have solutions in result, or they might still be found in a later iteration.
It is not clear to me why you first create a merged array of both input arrays. It does not seem to bring any benefit.
If you sort the input arrays, you can use a two-pointer system where you decide which one to move depending on whether the current sum is within limits or it is too great:
function getMoneySpent(keyboards, drives, b) {
keyboards = [...keyboards].sort((a, b) => b - a) // descending
drives = [...drives].sort((a, b) => a - b); // ascending
let k = keyboards.length - 1; // cheapest
let d = drives.length - 1; // most expensive
let maxSum = -1;
while (d >= 0 && k >= 0) {
let sum = keyboards[k] + drives[d];
if (sum === b) return b;
if (sum < b) {
if (sum > maxSum) maxSum = sum;
k--; // will increase sum
} else {
d--; // will decrease sum
}
}
return maxSum;
}

Related

How can I prevent a RangeError while running an algorithm that finds all permutations of a given word?

I've built a thesaurus-application in React that fetches data from a web-dictionary API and renders definitions, synonyms, and antonyms as collapsible lists when a user searches a word. I'd like to add a feature that will display all of the valid anagrams of a word that is searched (this isn't the problem right now, however).
I have written a recursive algorithm that finds all of the possible permutations of any given input, based on the number of possible permutations for that word. The only problem is, I encounter a RangeError when the input is any greater than 6 letters long. I know that my algorithm can and will find all permutations of an input greater than 6 characters long, but is hindered by the maximum-size of the call-stack.
I've attempted to use multiple different non-recursive algorithms that accomplish the same purpose from various other sources I've stumbled upon, and all but one encounter the same issue. If possible, however, I would like to refactor my solution to be viable, rather than copying the one working solution that I have found. I will display both my solution and the working solution for informational purposes.
My solution:
/* These next two helper functions can be ignored, I've included them in case
of your curiosity. However, they are unimportant to the problem at hand.
Both functions merely determine the total number of possible permutations for a given
input, which I use to determine how many times my final function should recurse */
// Helper function 1
const hasDuplicates = (str) => {
const letters = {};
str.split('').forEach(letter => {
if (letters[letter] !== undefined) letters[letter]++;
if (letters[letter] === undefined) letters[letter] = 1;
});
for (let key in letters) {
let currLetter = letters[key];
if (currLetter > 1) return letters;
};
return false;
};
// Helper function 2
const numPermutations = (str) => {
if (hasDuplicates(str) === false) {
let multiplier = 1;
for (let i = 1; i <= str.length; i++) multiplier *= i;
return multiplier;
};
const letters = hasDuplicates(str);
let multiplier = 1;
let divisor = 1;
let visited = new Set();
for (let i = 1; i <= str.length; i++) {
let currLetter = str[i];
if (letters[currLetter] > 1 && !visited.has(currLetter)) {
for (let j = 1; j <= letters[currLetter]; j++) {
divisor *= j;
};
visited.add(currLetter);
};
multiplier *= i;
};
return (multiplier / divisor);
};
// Final recursive function
const permutations = (string, finalArray = [], i = 0, visited = new Set()) => {
/* If the input consists of only two values and both are identical, we know that
further evaluation is unnecessary. */
if (string.length === 2) {
if (string.split('')[0] === string.split('')[1]) {
finalArray.push(string);
return finalArray;
};
};
if (string.length <= 2 && finalArray.length === string.length) return finalArray;
// Call to previous helper function which determines number of times we must recurse
const maxPermutations = numPermutations(string);
if (i === maxPermutations) return finalArray;
const splitString = string.split('');
// Scramble the letters of the string and rearrange them in a random order
for (let i = splitString.length - 1; i > 0; i--) {
let randNum = Math.floor(Math.random() * (i + 1));
let replacement = splitString[i];
splitString[i] = splitString[randNum];
splitString[randNum] = replacement;
};
if (!visited.has(splitString.join(''))) {
/* If we don't already have this random variation of the string in our array,
push it into our final array, add it to the set of strings we've encountered,
and increment our index variable to work towards the base case */
finalArray.push(splitString.join(''));
visited.add(splitString.join(''));
return permutations(string, finalArray, i += 1, visited);
};
/* If we have encountered the latest random variation of our string,
recurse without incrementing our index (does not work toward base case) */
return permutations(string, finalArray, i, visited);
};
Again, this works great for inputs less than 7 characters long. However, anything longer, and the maximum call stack size is exceeded. I am including the one solution I've found that works around this problem below, in hope that it may be able to shed light on a possible workaround for my solution. That being said, I don't understand how this solution works or why it works, only that it does. I'll use it in my application as a last resort, but I prefer to use my own work over the work of someone else.
function permutes(string) {
var s = string.split('').sort();
var res = [s.join('')]
while(true) {
var j = s.length - 2;
while (j != -1 && s[j] >= s[j + 1])
j--;
if(j == -1)
break;
var k = s.length - 1;
while(s[j] >= s[k])
k--;
[s[j], s[k]] = [s[k], s[j]];
var l = j + 1, r = s.length - 1;
while (l<r) {
[s[l], s[r]] = [s[r], s[l]];
l++;
r--;
}
res.push(s.join(''));
}
return res;
}
You should use a function named nextPermutation that only returns the next permutation in lexical order. This will save tons of memory.
Considering this answer all it takes is translate numbers to letters. Let's try.
var nextPermutation = function(word) {
var nums = word.split('');
function swap(index1, index2) {
var temp = nums[index1]
nums[index1] = nums[index2]
nums[index2] = temp;
}
function next_bigger_from(pos) {
var current = nums[pos];
var result = -1;
var min = null;
for (var i = pos + 1; i < len; i++) {
if (nums[i] > current) {
result = i;
min = nums[i];
}
}
return result;
}
function sort_from(pos) {
for (var i = pos; i < len - 1; i++) {
for (var j = i + 1; j < len; j++) {
if (nums[i] > nums[j]) {
swap(i, j)
}
}
}
}
var len = nums.length;
if (len < 2) {
console.log("" + nums)
return;
}
var rotator = 2; // from right
while (rotator <= len) {
var pos = len - rotator;
var pos2 = next_bigger_from(pos);
if (pos2 == -1) {
rotator += 1;
continue;
}
swap(pos, pos2);
sort_from(pos + 1);
return nums.join("");
}
nums = nums.sort();
return nums.join("");
};
var str = "ABCDEFGH"
for (var i = 0; i < 100; i++) {
console.log(str)
str = nextPermutation(str)
}
.as-console-wrapper {max-height: 100% !important}
You are trying to calculate all the permutations via random sampling with replacement. This can be modelled by the Coupon Collector's Problem. The expected number of trials to get them all via this method grows somewhat faster than n * log (n), where n is the total number of items you want to fetch. If you have 7 (all distinct) characters, the number of permutations will be 7!, or 5040, which means the expected number of tries before you hit them all is
[1, 2, 3, ... 5040] .reduce ((n, f) => n + 5040 / f, 0)
which is a bit over 45876. This is smaller if there are duplicated letters, of course.
Doing this recursively, means that you will likely hit recursion depth limits doing this. If you switched to an iterative loop, this would probably work for seven, but you will still quickly hit significant limits with such a technique.
If you want all permutations, but in a random order, I would suggest that you generate them all and shuffle the results.
Note that you could definitely simplify both your counting function and your generation function. To count them, we can use the mathematical fact that if there are a A's, b B's, ... and k K's the number of total permutations is
(a + b + ... + k)! / (a! * b! * ... * k!)
so with a simple count function that, for instance, converts "ABCDBBC" to {A: 1, B: 3, C: 2, D: 1}, and a trivial factorial function, we could simply write that fairly simply.
I know you'd prefer to use your own code, but if you want to see my implementation of this idea, you can expand this snippet:
const factorial = (n) => n < 2 ? 1 : n * factorial (n - 1)
const count = ([...s]) =>
s .reduce ((a, c) => ((a [c] = (a[c] || 0) + 1), a), {})
const numPermutations = (s) =>
Object .values (count (s)) .reduce ((n, f) => n / factorial (f), factorial (s .length))
console .log (numPermutations ('ABCDBBC')) //=> 420
// We probably don't call it enough to matter, but `factorial` is a good candidate for
// memoization. If you want to do that, it's simple enough:
//
// const factorial = ((memo = {}) =>
// (n) => n in memo ? memo [n] : memo [n] = n < 2 ? 1 : n * factorial (n - 1)
// )()
To directly find all the permutations, we might use a variant of the technique I used in another answer. That one doesn't take into account multiplicities. We could tweak it to stop collecting when we might start hitting duplicates. Again, expand the snippet if you want to see my implementation, with an explanation in the comments.
// Here `excluding` returns a copy of an array with the element at a particular index
// removed. Our `permutations` function returns a result containing only an empty array if
// the input is empty. Otherwise it loops through the letters, and, if it's the first
// instance of that letter removing it from consideration, recurring with the remaining
// letters and for each result, prepending this first letter to it. If it's not the first
// instance, we just return an empty result. This last is the twist from the original which
// blindly did the recursive step, and thus for `"AAB"` would return all six possible
// permutations, even though there are duplicates (`["AAB", "ABA", "AAB", "ABA", "BAA",
// "BAA"]`). By testing `xs .indexOf (x) == i`, we eliminate large swaths of the
// potential output.
const excluding = (i) => (xs) =>
[... xs .slice (0, i), ... xs .slice (i + 1)]
const permutations = ([...xs]) =>
xs .length == 0
? [[]]
: xs .flatMap ((x, i) =>
xs .indexOf (x) == i ? permutations (excluding (i) (xs)) .map (p => x + p) : []
)
console .log (permutations ('ABCDBBC'))
.as-console-wrapper {max-height: 100% !important; top: 0}

Least Common Multiple - for loop breaks down - javascript

I'm taking a course on FreeCodeCamp.org and the assignment is to find "Smallest Common Multiple". So I came up with a solution I think works and I does up to a certain point. Then the code just seems like it's breaking down. Here is my code:
function smallestCommons(arr) {
arr = arr.sort((a,b) => {return a - b;});
console.log(arr);
var truesec = false;
for(var a = arr[1]; truesec != true; a++){
for(var e = 1; e <= arr[1]; e++){
//console.log(a % e + " " + e);
if(a % e != 0){
truesec = false;
break;
}else{
truesec = true;
}
}
//console.log(truesec + " " + a);
if(truesec == true){
return a;
}
}
return a;
}
console.log(smallestCommons([23,18]));
This should return 6056820 according to their checklist but every time I check I get a different result I've gotten both 114461 & 122841 from the same code. Can somebody please tell me what is wrong with this?
Here is the assignment if it helps:
Intermediate Algorithm Scripting: Smallest Common Multiple
What your algorithm trying to do is find the common multiple between 1 and the greater number in the array, which might take a very long time. However, the question from the FreeCodeCamp asks you to find the common multiple between the two numbers in the array, so the result calculated from your algorithm does not match the tests.
To make your solution works, you can change
from for (var e = 1; e <= arr[1]; e++)
to for (var e = arr[0]; e <= arr[1]; e++)
in order to loop between two numbers in the array.
I would take a different approach to this problem:
create function to get all prime factors
create array of prime factor of all number between a[0] and a[1]
reduce the array as the biggest power for each prime factor.
multiple all the prime factor left in the array
Your approach will take O(k*a[1]) when k is the answer - and k can be very high... This approach will take O((a[1])^2)
Consider the following code:
function smallestCommons2(arr) {
arr.sort((a,b) => {return a - b;});
let factors = [];
for(let i = arr[0]; i <= arr[1]; i++)
factors.push(findPrimeFactors(i));
let reduced = reduceFactors(factors);
let ans = 1;
for (let i in reduced)
ans *= Math.pow(i, reduced[i]);
return ans;
}
function reduceFactors(factorsArr) {
let factorObject = {};
for (let i in factorsArr) {
for(let key in factorsArr[i]) {
if (!(key in factorObject) || factorObject[key] < factorsArr[i][key])
factorObject[key] = factorsArr[i][key];
}
}
return factorObject;
}
function findPrimeFactors (num) {
var primeFactors = [];
while (num % 2 === 0) {
primeFactors.push(2);
num = num / 2;
}
var sqrtNum = Math.sqrt(num);
for (var i = 3; i <= sqrtNum; i++) {
while (num % i === 0) {
primeFactors.push(i);
num = num / i;
}
}
if (num > 2)
primeFactors.push(num);
let factorObject = {};
for (let item of primeFactors) {
if (item in factorObject)
factorObject[item] += 1;
else factorObject[item] = 1;
}
return factorObject;
}
console.log(smallestCommons2([23,18]));
This code will output 6056820 in sec
Edited - found a post that do the same thing in a better way

quick sort in javascript

I have this working insertion sort javascript code.
Array.prototype.insertionSort = function() {
var A = this;
var time = 0;
var n = A.length;
for (var i = 1; i < n; i++) {
var v = A[i];
var j = i-1;
while (j >= 0 && A[j] > v) {
A[j+1] = A[j];
j--;
var temp = new Array(this);
setTimeout(callback(JSON.stringify(temp)), 500*(time++));
}
A[j+1] = v;
var temp = new Array(this);
setTimeout(callback(JSON.stringify(temp)), 500*(time++));
}
return time;
}
I need something similar for quciksort, but I don't know how to do it. Can someone help me, please?
This might be the late posting, but I hope this may help somebody. QuickSort is a Divide and Conquer algorithm. It picks an element as pivot and partitions the given array around the picked pivot. You can select pivot in the following ways.
a)pick the first element as the pivot(Implemented below) b)pick the last element as pivot c)Pick a random element as pivot.d)pick median as a pivot.
if your array is already sorted then time complexity would be O(n^2) but for the average and best case it is O(N log N). It is in place algorithm and nonstable(as partitioning does one of the long-range exchanges). In some cases quicksort might take quadratic time. Quicksort has more overhead even for tiny arrays for sizes less than 10-20. If you use insertion sort for the small size of arrays then you might reduce the processing time by 15-20 %. Sharing my code below, also if you want to reduce more processing time then try to estimate partitioning element to be middle of an array.
class QuickSort{
constructor(){
this.cutoff = 10;
}
partition(arr, lo, hi){
let i = lo, j = hi+1;
debugger;
while(true){
while(arr[++i] < arr[lo]) if(i == hi) break;
while(arr[lo] < arr[--j]) if(j == lo) break;
if(i >= j) break;
this.swap(arr, i, j);
}
this.swap(arr, lo, j);
return j;
}
swap(arr, i, j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
sort(arr, lo, hi){
//if(hi <= lo) return;
if((this.cutoff + lo) -1 >= hi){
let insertionSort = new InsertionSort();
insertionSort.sort(arr); return;
}
console.log('Inside Quick Sort');
let j = this.partition(arr, lo, hi);
this.sort(arr, lo, j-1);
this.sort(arr, j+1, hi);
}
shuffle(arr) {
let n = arr.length;
for (let i = 0; i < n; i++) {
// choose index uniformly in [0, i]
let r = Math.floor(Math.random() * (i + 1));
this.swap(arr, i, r);
}
console.log('After uniform random Shuffle');
console.log(arr);
this.sort(arr, 0, n-1);
}
}
class InsertionSort{
constructor(){
this.quickSort = new QuickSort();
}
sort(arr){
console.log("Inside Insertion sort");
for(let i = 1; i < arr.length; i++){
for(let j = i; j > 0; j--){
if(arr[j-1] > arr[j]){
this.quickSort.swap(arr, j, j-1);
}
}
}
}
}
let arr = [101, 22,4,22,2,7,9,10,49,101,-1,4,1,6,99];
console.log('Before sorting an array');
console.log(arr);
let quickSort = new QuickSort();
quickSort.shuffle(arr);
console.log('After Sorting an array');
console.log(arr);
you can get to know the time complexity of from this post time complexity
The Wikipedia article on Quick Sort is pretty thorough and even includes a few pseudocode implementations.
Wikipedia summarizes the problem like so:
Quicksort is a divide and conquer algorithm. Quicksort first divides a
large array into two smaller sub-arrays: the low elements and the high
elements. Quicksort can then recursively sort the sub-arrays.
The steps are:
Pick an element, called a pivot, from the array.
Partitioning: reorder the array so that all elements with values less than the pivot come before the pivot, while all elements with values greater than the pivot come after it (equal values can go either way). After this partitioning, the pivot is in its final position. This is called the partition operation.
Recursively apply the above steps to the sub-array of elements with smaller values and separately to the sub-array of elements with greater values.
The base case of the recursion is arrays of size zero or one, which are in order by definition, so they never need to be sorted.
The pivot selection and partitioning steps can be done in several
different ways; the choice of specific implementation schemes greatly
affects the algorithm's performance.
And just a heads-up, I remember off-by-one errors being the biggest headache with this problem when I did it in school, so if you don't get the right answer right away, double-check your pivot selection and partitioning logic.
You should check google before posting a question: Quicksort is a very common algorithm and you have plenty of resources describing it.
function swap(items, firstIndex, secondIndex){
var temp = items[firstIndex];
items[firstIndex] = items[secondIndex];
items[secondIndex] = temp;
}
function partition(items, left, right) {
var pivot = items[Math.floor((right + left) / 2)],
i = left,
j = right;
while (i <= j) {
while (items[i] < pivot) {
i++;
}
while (items[j] > pivot) {
j--;
}
if (i <= j) {
swap(items, i, j);
i++;
j--;
}
}
return i;
}
function quickSort(items, left, right) {
var index;
if (items.length > 1) {
left = typeof left != "number" ? 0 : left;
right = typeof right != "number" ? items.length - 1 : right;
index = partition(items, left, right);
if (left < index - 1) {
quickSort(items, left, index - 1);
}
if (index < right) {
quickSort(items, index, right);
}
}
return items;
}
// first call
var result = quickSort(items);
Code credits: N.C.Zakas
Furthermore, note that Quicksort is used by V8 when calling Array.prototype.sort() on arrays > 10 items (V8 source). On smaller arrays, InsertionShort is actually faster.
heres a short version of quick sort written in pure JS!
as seen in Intro To Algorithms
var partition = function (arr, low, high) {
var x = arr[high]
var i = low - 1
for (var j = low; j <= high - 1; j++) {
if (arr[j] <= x) {
i++
var temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
}
var temp = arr[i + 1]
arr[i + 1] = arr[high]
arr[high] = temp
return i + 1
}
var quickSort = function (arr, low, high) {
if (low < high) {
index = partition(arr,low,high)
if (low < index-1) quickSort(arr,low,index-1)
if (index+1 < high) quickSort(arr,index+1,high)
}
}
var list2 = [1000,13,12,1001,82,1,2,4,3,0]
console.log(quickSort(list2,0,list2.length))
also on my GitHub

Codility "PermMissingElem" Solution in Javascript

A codility problem asks to find the missing number in zero-indexed array A consisting of N different integers.
E.g.
Arr[0] = 2
Arr[1] = 3
Arr[2] = 1
Arr[3] = 4
Arr[4] = 6
I previously submitted a solution that first sorts the array and then performs a forEach function returning the value +1 where the array difference between elements is more than 1, however this doesn't get the 100 points.
Is there a way to improve this?
Here is 100% javascript solution:
function solution(A) {
if (!A.length) return 1;
let n = A.length + 1;
return (n + (n * n - n) / 2) - A.reduce((a, b) => a + b);
}
We return 1 if the given array is empty, which is the missing element in an empty array.
Next we calculate the 'ordinary' series sum, assuming the first element in the series is always 1. Then we find the difference between the given array and the full series, and return it. This is the missing element.
The mathematical function I used here are series sum, and last element:
Sn = (n/2)*(a1 + an)
an = a1 + (n - 1)*d
Get 100 in correctness and performance using this function
function solution(A) {
// write your code in JavaScript (Node.js 4.0.0)
var size = A.length;
var sum = (size + 1) * (size + 2) / 2;
for (i = 0; i < size; i++) {
sum -= A[i];
}
return sum;
}
Easy if you use the Gauss formula to calculate the sum of the first N consecutive numbers:
function solution(A) {
var np1, perfectSum, sum;
if (!A || A.length == 0) {
return 1;
}
np1 = A.length + 1;
// Gauss formula
perfectSum = np1 * (1 + np1) / 2;
// Sum the numbers we have
sum = A.reduce((prev, current) => prev + current);
return perfectSum - sum;
}
From the sum of first natural numbers formula we have
now since the N item for us in the task is (N+1) we substitue n with n+1 and we get
with the formula above we can calculate the sum of numbers from 1 to n+1, since in between these numbers there is the missing number, now what we can do is we can start iterating through the given array A and subtracting the array item from the sum of numbers. The ending sum is the item which was missing in the array. hence:
function solution(A) {
var n = A.length;
// using formula of first natural numbers
var sum = (n + 1) * (n + 2) / 2;
for (var i = 0; i < n; i++) {
sum -= A[i];
}
return sum;
}
No Gauss formula, only simple and plain separate for loops that give an O(N) or O(N * log(N)) and 100% score:
function solution(A) {
if(!A.length){
return 1; //Just because if empty this is the only one missing.
}
let fullSum = 0;
let sum = 0;
for(let i = 0; i <= A.length; i++){
fullSum += i+1;
}
for(let i = 0; i < A.length; i++){
sum += A[i];
}
return fullSum - sum;
}
Try utilizing Math.min , Math.max , while loop
var Arr = [];
Arr[0] = 2
Arr[1] = 3
Arr[2] = 1
Arr[3] = 4
Arr[4] = 6
var min = Math.min.apply(Math, Arr),
max = Math.max.apply(Math, Arr),
n = max - 1;
while (n > min) {
if (Arr.indexOf(n) === -1) {
console.log(n);
break;
}
--n;
}
This should be work good:
function solution(A) {
// Size of the A array
const size = A.length;
// sum of the current values
const arrSum = A.reduce((a, b) => a + b, 0);
// sum of all values including the missing number
const sum = (size + 1) * (size + 2) / 2;
// return substruction of all - current
return (sum - arrSum);
}
This got me 100%
function solution(A) {
if (A.length === 0 || !A) {
return 1;
}
A.sort((a, b) => a - b);
let count = A[0];
if (count !== 1) { return 1 }
for (let i = 0; i <= A.length; i++) {
if (A[i + 1] === count + 1) {
count ++;
continue
}
return count + 1;
}
}
// you can write to stdout for debugging purposes, e.g.
// console.log('this is a debug message');
function solution(A) {
if (!A.length) return 1;
A = A.sort((a, b) => a - b);
for (let i = 0; i < A.length + 1; i++) {
if (A[i] !== i + 1) {
return i + 1;
}
}
}
My 100% JavaScript solution:
function solution(A) {
const N = A.length;
// use the Gauss formula
const sumNatural = (N + 1) * (N + 2) / 2;
// actual sum with the missing number (smaller than sumNatural above)
const actualSum = A.reduce((sum, num) => sum += num, 0);
// the difference between sums is the missing number
return sumNatural - actualSum;
}
I wonder why there isn't any answer using a hashtable.
It's obvious that we need to iterate this array from start to end.
Therefore, best solution we can have is O(n).
I simply map numbers, and access them with O(1) in another iteration.
If all numbers are tagged as true, it means it's either an empty array, or it doesn't contain missing number. Either way length + 1 returns the expected output.
It returns 1 for [], and it returns 3 for [1,2].
// you can write to stdout for debugging purposes, e.g.
function solution(A) {
// write your code in JavaScript (Node.js 8.9.4)
let nums = new Map()
for (let i = 0; i < A.length; i++) {
nums[A[i]] = true;
}
for (let i = 1; i < A.length + 1; i++) {
if (nums[i]) { continue; }
else { return i;}
}
return A.length + 1;
}
function solution(A) {
// write your code in JavaScript (Node.js 8.9.4)
const n = A.length+1
return (n*(n+1)/2) - A.reduce((a, b) => a + b, 0)
}
Explanation:
The formula for sum of natural numbers => n(n+1)/2
where n is the last number or last nth term.
In our case, n will be our array.length. But the question states that exactly one item is missing, meaning the last nth term is array.length +1.
To find the expected sum of all our natural numbers,
We can deduct the total of the available numbers (A.reduce((a, b) => a + b, 0)) from the expected sum n(n+1)/2 to arrive at the missing number.
I had the same problem with my code:
function solution(A) {
var i, next;
A.sort();
next = 1;
for (i=0; i<A.length; i++){
if (A[i] != next) return next;
next++;
}
return next;
}
Altough it scored 100% in correctness, it returned wrong answer in all the performance tests.
The same code in C receives 100% on both:
int cmpfunc (const void * a, const void * b){
return ( *(int*)a - *(int*)b );
}
int solution(int a[], int n) {
int i, next;
qsort(a, n, sizeof(int), cmpfunc);
next = 1;
for (i=0; i<n; i++){
if (a[i] != next) return next;
next++;
}
return next;
}
I got an alternative 100% correctness/performance solution without the Gauss formula, sorting the array first instead:
function solution(A) {
A.sort((a, b) => a-b);
for(let i=0; i<A.length; i++){
if(A[i] != i+1) {
return 0;
}
}
return 1;
}

How to find the least common multiple of a range of numbers?

Given an array of two numbers, let them define the start and end of a range of numbers. For example, [2,6] means the range 2,3,4,5,6. I want to write javascript code to find the least common multiple for the range. My code below works for small ranges only, not something like [1,13] (which is the range 1,2,3,4,5,6,7,8,9,10,11,12,13), which causes a stack overflow. How can I efficiently find the least common multiple of a range?
function leastCommonMultiple(arr) {
var minn, max;
if ( arr[0] > arr[1] ) {
minn = arr[1];
max = arr[0];
} else {
minn = arr[0];
max = arr[1];
}
function repeatRecurse(min, max, scm) {
if ( scm % min === 0 && min < max ) {
return repeatRecurse(min+1, max, scm);
} else if ( scm % min !== 0 && min < max ) {
return repeatRecurse(minn, max, scm+max);
}
return scm;
}
return repeatRecurse(minn, max, max);
}
I think this gets the job done.
function leastCommonMultiple(min, max) {
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.push(i);
}
return arr;
}
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
var multiple = min;
range(min, max).forEach(function(n) {
multiple = lcm(multiple, n);
});
return multiple;
}
leastCommonMultiple(1, 13); // => 360360
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
LCM function for a range [a, b]
// Euclid algorithm for Greates Common Divisor
function gcd(a, b)
{
return !b ? a : gcd(b, a % b);
}
// Least Common Multiple function
function lcm(a, b)
{
return a * (b / gcd(a,b));
}
// LCM of all numbers in the range of arr=[a, b]
function range_lcm(arr)
{
// Swap [big, small] to [small, big]
if(arr[0] > arr[1]) (arr = [arr[1], arr[0]]);
for(x = result = arr[0]; x <= arr[1]; x++) {
result = lcm(x, result);
}
return result;
}
alert(range_lcm([8, 5])); // Returns 840
As this question has recently been revived, here's what I think is a simpler take on the question, writing very simple helper functions to calculate the greatest common divisor of two integers (gcd), to calculate the least common multiple of two integers (lcm), to calculate the least common multiple of an array of integers (lcmAll), to generate the range of integers between two given integers (rng), and finally, in our main function, to calculate the least common multiple of the range of integers between two given integers (lcmRng):
const gcd = (a, b) => b == 0 ? a : gcd (b, a % b)
const lcm = (a, b) => a / gcd (a, b) * b
const lcmAll = (ns) => ns .reduce (lcm, 1)
const rng = (lo, hi) => [...Array (hi - lo + 1)] .map ((_, i) => lo + i)
const lcmRng = (lo, hi) => lcmAll (rng (lo, hi))
console .log (lcmRng (1, 13))
All of these functions are simple. Although the question was tagged recursion, only gcdis recursive. If this is an attempt to play with recursion, we could rewrite lcmAll in a recursive manner with something like this:
const lcmAll = (ns) =>
ns.length == 0
? 1
: lcm(ns[0], lcmAll(ns .slice (1)))
Although I'm a big fan of recursion, I see no other reason to choose the recursive version here over the reduce one. In this case, reduce is cleaner.
And finally, if you really want the API originally requested where the range bounds are passed in an array, you could write one more wrapper:
const leastCommonMultiple = ([lo, hi]) => lcmRng (lo, hi)
leastCommonMultiple ([1, 13]) //=> 360360
I found the other answers to be somewhat confusing while I was figuring out the best way to do this with just two numbers, so I looked found the most optimal solution on Wikipedia.
https://en.wikipedia.org/wiki/Least_common_multiple#Calculation
The most efficient way to find the least common multiple of two numbers is (a * b) / greatestCommonDivisor(a, b);
To do this we need to calculate the greatest common denominator. The most efficient way to do that is using Euclid's algorithm.
https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclid's_algorithm
Here is the complete solution for two numbers in case anyone else lands on this question but only needs to calculate for two numbers:
const leastCommonMultiple = (a, b) => (a * b) / greatestCommonDivisor(a, b);
const greatestCommonDivisor = (a, b) => {
const remainder = a % b;
if (remainder === 0) return b;
return greatestCommonDivisor(b, remainder);
};
Mine is not as fancy as the other answers but I think it is easy to read.
function smallestCommons(arr) {
//order our array so we know which number is smallest and which is largest
var sortedArr = arr.sort(sortNumber),
//the smallest common multiple that leaves no remainder when divided by all the numbers in the rang
smallestCommon = 0,
//smallest multiple will always be the largest number * 1;
multiple = sortedArr[1];
while(smallestCommon === 0) {
//check all numbers in our range
for(var i = sortedArr[0]; i <= sortedArr[1]; i++ ){
if(multiple % i !== 0 ){
//if we find even one value between our set that is not perfectly divisible, we can skip to the next multiple
break;
}
//if we make it all the way to the last value (sortedArr[1]) then we know that this multiple was perfectly divisible into all values in the range
if(i == sortedArr[1]){
smallestCommon = multiple;
}
}
//move to the next multiple, we can just add the highest number.
multiple += sortedArr[1];
}
console.log(smallestCommon);
return smallestCommon;
}
function sortNumber(a, b) {
return a - b;
}
smallestCommons([1, 5]); // should return 60.
smallestCommons([5, 1]); // should return 60.
smallestCommons([1, 13]); // should return 360360.
smallestCommons([23, 18]); // should return 6056820.
Edit: Turned answer into snippet.
This is a non-recursive version of your original approach.
function smallestCommons(arr) {
// Sort the array
arr = arr.sort(function (a, b) {return a - b}); // numeric comparison;
var min = arr[0];
var max = arr[1];
var numbers = [];
var count = 0;
//Here push the range of values into an array
for (var i = min; i <= max; i++) {
numbers.push(i);
}
//Here freeze a multiple candidate starting from the biggest array value - call it j
for (var j = max; j <= 1000000; j+=max) {
//I increase the denominator from min to max
for (var k = arr[0]; k <= arr[1]; k++) {
if (j % k === 0) { // every time the modulus is 0 increase a counting
count++; // variable
}
}
//If the counting variable equals the lenght of the range, this candidate is the least common value
if (count === numbers.length) {
return j;
}
else{
count = 0; // set count to 0 in order to test another candidate
}
}
}
alert(smallestCommons([1, 5]));
Hey I came across this page and wanted to share my solution :)
function smallestCommons(arr) {
var max = Math.max(arr[0], arr[1]),
min = Math.min(arr[0], arr[1]),
i = 1;
while (true) {
var count = 0;
for (j = min; j < max; j++) {
if (max * i % j !== 0) {
break;
}
count++;
}
if (count === (max - min)) {
alert(max * i);
return max * i;
}
i++;
}
}
smallestCommons([23, 18]);
function leastCommonMultiple(arr) {
/*
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.push(i);
}
return arr;
}
*/
var min, range;
range = arr;
if(arr[0] > arr[1]){
min = arr[1];
}
else{
min = arr[0]
}
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
var multiple = min;
range.forEach(function(n) {
multiple = lcm(multiple, n);
});
return multiple;
}
console.log( leastCommonMultiple([1, 13]) )
Well played on the solution. I think I got one that might be abit shorter just for future reference but ill definatly look into yours
function LCM(arrayRange) {
var newArr = [];
for (var j = arrayRange[0]; j <= arrayRange[1]; j++){
newArr.push(j);
}
var a = Math.abs(newArr[0]);
for (var i = 1; i < newArr.length; i++) {
var b = Math.abs(newArr[i]),
c = a;
while (a && b) {
a > b ? a %= b : b %= a;
}
a = Math.abs(c * newArr[i] / (a + b))
}
return console.log(a);
}
LCM([1,5]);
You may have originally had a stack overflow because of a typo: you switched between min and minn in the middle of repeatRecurse (you would have caught that if repeatRecurse hadn’t been defined in the outer function). With that fixed, repeatRecurse(1,13,13) returns 156.
The obvious answer to avoiding a stack overflow is to turn a recursive function into a non-recursive function. You can accomplish that by doing:
function repeatRecurse(min, max, scm) {
while ( min < max ) {
while ( scm % min !== 0 ) {
scm += max;
}
min++;
}
}
But perhaps you can see the mistake at this point: you’re not ensuring that scm is still divisible by the elements that came before min. For example, repeatRecurse(3,5,5)=repeatRecurse(4,5,15)=20. Instead of adding max, you want to replace scm with its least common multiple with min. You can use rgbchris’s gcd (for integers, !b is the same thing as b===0). If you want to keep the tail optimization (although I don’t think any javascript engine has tail optimization), you’d end up with:
function repeatRecurse(min, max, scm) {
if ( min < max ) {
return repeatRecurse(min+1, max, lcm(scm,min));
}
return scm;
}
Or without the recursion:
function repeatRecurse(min,max,scm) {
while ( min < max ) {
scm = lcm(scm,min);
min++;
}
return scm;
}
This is essentially equivalent to rgbchris’s solution. A more elegant method may be divide and conquer:
function repeatRecurse(min,max) {
if ( min === max ) {
return min;
}
var middle = Math.floor((min+max)/2);
return lcm(repeatRecurse(min,middle),repeatRecurse(middle+1,max));
}
I would recommend moving away from the original argument being an array of two numbers. For one thing, it ends up causing you to talk about two different arrays: [min,max] and the range array. For another thing, it would be very easy to pass a longer array and never realize you’ve done something wrong. It’s also requiring several lines of code to determine the min and max, when those should have been determined by the caller.
Finally, if you’ll be working with truly large numbers, it may be better to find the least common multiple using the prime factorization of the numbers.
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.push(i);
}
return arr;
}
function gcd (x, y) {
return (x % y === 0) ? y : gcd(y, x%y);
}
function lcm (x, y) {
return (x * y) / gcd(x, y);
}
function lcmForArr (min, max) {
var arr = range(min, max);
return arr.reduce(function(x, y) {
return lcm(x, y);
});
}
range(10, 15); // [10, 11, 12, 13, 14, 15]
gcd(10, 15); // 5
lcm(10, 15); // 30
lcmForArr(10, 15); //60060
How about:
// Euclid Algorithm for the Greatest Common Denominator
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
// Euclid Algorithm for the Least Common Multiple
function lcm(a, b) {
return a * (b / gcd(a, b));
}
// LCM of all numbers in the range of arr = [a, b];
function smallestCommons(arr) {
var i, result;
// large to small - small to large
if (arr[0] > arr[1]) {
arr.reverse();
} // only happens once. Means that the order of the arr reversed.
for (i = result = arr[0]; i <= arr[1]; i++) { // all numbers up to arr[1] are arr[0].
result = lcm(i, result); // lcm() makes arr int an integer because of the arithmetic operator.
}
return result;
}
smallestCommons([5, 1]); // returns 60
function lcm(arr) {
var max = Math.max(arr[0],arr[1]),
min = Math.min(arr[0],arr[1]),
lcm = max;
var calcLcm = function(a,b){
var mult=1;
for(var j=1; j<=a; j++){
mult=b*j;
if(mult%a === 0){
return mult;
}
}
};
for(var i=max-1;i>=min;i--){
lcm=calcLcm(i,lcm);
}
return lcm;
}
lcm([1,13]); //should return 360360.
/*Function to calculate sequential numbers
in the range between the arg values, both inclusive.*/
function smallestCommons(arg1, arg2) {
if(arg1>arg2) { // Swap arg1 and arg2 if arg1 is greater than arg2
var temp = arg1;
arg1 = arg2;
arg2 =temp;
}
/*
Helper function to calculate greatest common divisor (gcd)
implementing Euclidean algorithm */
function gcd(a, b) {
return b===0 ? a : gcd(b, a % b);
}
/*
Helper function to calculate lowest common multiple (lcm)
of any two numbers using gcd function above */
function lcm(a,b){
return (a*b)/gcd(a,b);
}
var total = arg1; // copy min value
for(var i=arg1;i<arg2;i++){
total = lcm(total,i+1);
}
//return that total
return total;
}
/*Yes, there are many solutions that can get the job done.
Check this out, same approach but different view point.
*/
console.log(smallestCommons(13,1)); //360360
Here's my solution. I hope you will find it easy to follow:
function smallestCommons(arr) {
var min = Math.min(arr[0], arr[1]);
var max = Math.max(arr[0], arr[1]);
var smallestCommon = min * max;
var doneCalc = 0;
while (doneCalc === 0) {
for (var i = min; i <= max; i++) {
if (smallestCommon % i !== 0) {
smallestCommon += max;
doneCalc = 0;
break;
}
else {
doneCalc = 1;
}
}
}
return smallestCommon;
}
Here is another nonrecursive for-loop solution
function smallestCommons(arr) {
var biggestNum = arr[0];
var smallestNum = arr[1];
var thirdNum;
//make sure biggestNum is always the largest
if (biggestNum < smallestNum) {
thirdNum = biggestNum;
biggestNum = smallestNum;
smallestNum = thirdNum;
}
var arrNum = [];
var count = 0;
var y = biggestNum;
// making array with all the numbers fom smallest to biggest
for (var i = smallestNum; i <= biggestNum; i += 1) {
arrNum.push(i);
}
for (var z = 0; z <= arrNum.length; z += 1) {
//noprotect
for (y; y < 10000000; y += 1) {
if (y % arrNum[z] === 0) {
count += 1;
break;
}
else if (count === arrNum.length) {
console.log(y);
return y;
}
else {
count = 0;
z = 0;
}
}
}
}
smallestCommons([23, 18]);
function smallestCommons(arr) {
var sortedArr = arr.sort(); // sort array first
var tempArr = []; // create an empty array to store the array range
var a = sortedArr[0];
var b = sortedArr[1];
for(var i = a; i <= b; i++){
tempArr.push(i);
}
// find the lcm of 2 nums using the Euclid's algorithm
function gcd(a, b){
while (b){
var temp = b;
b = a % b;
a = temp;
}
return a;
}
function lcm(a, b){
return Math.abs((a * b) / gcd(a, b));
}
var lcmRange = tempArr.reduce(lcm);
return lcmRange;
}
function smallestCommons(arr) {
let smallest, biggest, min;
arr.reduce(function (a, b) {
biggest = Math.max(a, b);
});
const max = biggest;
arr.reduce(function (a, b) {
smallest = Math.min(a, b);
min = smallest;
});
check: while (true) {
biggest += max;
for (min = smallest; min < max; min++) {
if (biggest % min != 0) {
continue check;
}
if (min == (max - 1) && biggest % min == 0) {
console.warn('found one');
return biggest;
}
}
}
}
function smallestCommons(arr) {
let min = Math.min(arr[0], arr[1]);
let max = Math.max(arr[0], arr[1]);
let scm = max;
//calc lcm of two numbers:a,b;
const calcLcm = function(a, b) {
let minValue = Math.min(a, b);
let maxValue = Math.max(a, b);
let lcm = maxValue;
while (lcm % minValue !== 0) {
lcm += maxValue;
}
return lcm;
}
//calc scm in range of arr;
for (let i = max; i >= min; i--) {
scm = calcLcm(scm, i);
}
console.log(scm);
return scm;
}
smallestCommons([1, 13]);
this is another very simple way and have low complexity.
function smallestCommons(arr) {
let smallestNum = arr[0] < arr[1] ? arr[0] : arr[1];
let greatestNum = arr[0] > arr[1] ? arr[0] : arr[1];
let initalsArr = [];
for(let i = smallestNum; i <= greatestNum; i++){
initalsArr.push(i);
}
let notFoundFlag = true;
let gNMltpl = 0;
let filteredArrLen;
while(notFoundFlag){
gNMltpl += greatestNum;
filteredArrLen = initalsArr.filter((num)=>{
return (gNMltpl / num) === Math.floor((gNMltpl / num))
}).length;
if(initalsArr.length == filteredArrLen){
notFoundFlag = false;
}
}
return gNMltpl;
}
My solution using es6 feature is
Lcm of given numbers
const gcd = (a, b) => (!b ? a : gcd(b, a % b));
const lcm = (a, b) => a * (b / gcd(a, b));
const getLcm = (arr) => {
const numbers = arr.sort((a, b) => parseInt(a) - parseInt(b));
let result = parseInt(numbers[0]);
for (let i = 1; i < numbers.length; i++) {
result = lcm(parseInt(result), parseInt(numbers[i + 1]));
}
return result;
};
Hcf of given numbers
const getHcf = (arr) => {
const numbers = arr.sort((a, b) => parseInt(a) - parseInt(b));
let result = parseInt(numbers[0]);
for (let i = 1; i < numbers.length; i++) {
result = gcd(parseInt(numbers[i]), parseInt(result));
}
return result;
};
Call like this
console.log(getLcm([20, 15, 10, 40])). Answer 120
console.log(getHcf([2, 4, 6, 8, 16])). Answer 2
I also found myself working on this challenge on my freeCodeCamp JavaScript Certification. This is what I have been able to come up with:
function smallestCommons(arr) {
let newArr = [];
// create a new array from arr [min, min + 1,......., max - 1, max]
for (let i = Math.min(...arr); i <= Math.max(...arr); i++){
newArr.push(i);
}
// let the max of newArr be the smallestCommonMultiple initially
let largest = Math.max(...newArr);
let smallestCommonMultiple = largest;
// If the supposedly smallestCommonMultiple fail on any of elements in
//newArr add the max element until we find the smallestCommonMultiple.
while (newArr.some(element => smallestCommonMultiple % element !== 0)){
smallestCommonMultiple += largest;
}
return smallestCommonMultiple;
}
console.log(smallestCommons([23, 18]));
i think it will work.
var a = [2, 6];
function getTotalX(a) {
var num = 1e15;
var i;
var arr = [];
for (i = 1; i <=num ; i++){
arr.push(i);
}
for (i = 0; i < a.length; i++){
var filterArr = arr.filter((val, ind, arr) => (val % a[i] === 0));
}
console.log(filterArr[0]); // will return 6
}
I've made a similar function in typescript that does the same task but only without recursion...
function findLowestCommonMultipleBetween(start: number, end: number): number {
let numbers: number[] = [];
for (let i = start; i <= end; i++) {
numbers.push(i);
}
for (let i = 1; true; i++) {
let divisor = end * i;
if (numbers.every((number) => divisor % number == 0)) {
return divisor;
}
}
}
function smallestCommons(arr) {
let min = Math.min(...arr);
let max = Math.max(...arr);
let rangArr = [];
for(let i = min; i <= max; i++) rangArr.push(i);
let smallestCommon = max;
while(!rangArr.every(e => smallestCommon % e === 0)){
smallestCommon += max;
}
return smallestCommon;
}
console.log(smallestCommons([1, 13]));
function smallestCommons(arr) {
arr = arr.sort((a, b) => a - b)
let range = []
for (let i = arr[0]; i <= arr[1]; i++) {
range.push(i)
}
for(let i = arr[1]; ; i++){
if(range.every((num => i % num == 0))){
return i
}
}
}
function smallestCommons(arr) {
// Kind of a brute force method, It's not fancy but it's very simple and easy to read :P
// make an array with all the numbers in the range.
let numbersArr = [];
for (let i = Math.min(...arr); i <= Math.max(...arr); i++) {
numbersArr.push(i);
}
// keep multiplying the biggest number until it's divisible by all the numbers in the numbersArr array.
let scm = Math.max(...arr);
while (true) {
if (numbersArr.every(num => scm % num === 0)) {
return scm;
} else {
scm += Math.max(...arr);
}
}
}
smallestCommons([2, 10]); // returns 2520.
smallestCommons([1, 13]); // returns 360360.
smallestCommons([23, 18]); // returns 6056820.
function leastCommonMultiple(arr) {
// Setup
const [min, max] = arr.sort((a, b) => a - b);
// Largest possible value for LCM
let upperBound = 1;
for (let i = min; i <= max; i++) {
upperBound *= i;
}
// Test all multiples of 'max'
for (let multiple = max; multiple <= upperBound; multiple += max) {
// Check if every value in range divides 'multiple'
let divisorCount = 0;
for (let i = min; i <= max; i++) {
// Count divisors
if (multiple % i === 0) {
divisorCount += 1;
}
}
if (divisorCount === max - min + 1) {
return multiple;
}
}
}
//for a test
leastCommonMultiple([1, 5]);

Categories