I'm trying to script a function that takes two numbers and returns the smallest common multiple that is also divisible by all the numbers between those numbers, what I've got only works for 1,1 through 1,12, but for some reason stops working at 1,13. Other set like 12,14 work but I can't figure out why or what the pattern is.
function smallestCommons(arr) {
arr.sort(function(a, b) {
return a-b;
});
var arr1 = [];
var arr2 = [];
for (var k = arr[0]; k<=arr[1]; k++) {
arr1.push(k);
}
function remainder(val1, val2) {
return val1%val2;
}
var b = arr1.reduce(function(a, b) {
return a*b;
});
var i = arr1[arr1.length-1]*arr1[arr1.length-2];
while (i<=b) {
for (var m = 0; m<arr1.length; m++) {
var a = remainder(i, arr1[m]);
arr2.push(a);
}
var answer = arr2.reduce(function(c, d) {
return c+d;
});
if (answer === 0) {
return i;
} else {
arr2 = [];
i++;
}
}
}
I guess you can do as follows in JavaScript; It can calculate the common LCM up to an 216 item array, such as [1,2,3,...,216] in less than 0.25 ms.
function gcd(a,b){
var t = 0;
a < b && (t = b, b = a, a = t); // swap them if a < b
t = a%b;
return t ? gcd(b,t) : b;
}
function lcm(a,b){
return a/gcd(a,b)*b;
}
var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13],
brr = Array(216).fill().map((_,i) => i+1), // limit before Infinity
result = arr.reduce(lcm);
console.log(result);
console.time("limit");
result = brr.reduce(lcm);
console.timeEnd("limit");
console.log(result);
A way is to keep multiplying the largest number in your range with an increasing number and check if all the others are divisible by that. If yes, return that or continue the loop.
Here is my solution in typescript...
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;
}
}
}
...but for larger ranges, this is a more efficient answer :)
As far as I can tell your algorithm is giving you a correct answer.
I am far from being a professional programmer so anyone who wants please give options to improve my code or its style :)
If you want to be able to check for the answer yourself you can check this fiddle:
https://jsfiddle.net/cowCrazy/Ld8khrx7/
function multiplyDict(arr) {
arr.sort(function (a, b) {
return a - b;
});
if (arr[0] === 1) {
arr[0] = 2;
}
var currentArr = [];
for (var i = arr[0]; i <= arr[1]; i++) {
currentArr.push(i);
}
var primeDivs = allPrimes(arr[1]);
var divsDict = {};
for (var j = currentArr[0]; j <= currentArr[currentArr.length -1]; j++){
divsDict[j] = [];
if (primeDivs.indexOf(j) > -1) {
divsDict[j].push(j);
} else {
var x = j;
for (var n = 2; n <= Math.floor(j / 2); n++) {
if (x % n === 0) {
divsDict[j].push(n);
x = x / n;
n--;
continue;
}
}
}
}
return divsDict;
}
function allPrimes(num) {
var primeArr = [];
var smallestDiv = 2;
loopi:
for (var i = 2; i <= num; i++) {
loopj:
for (var j = smallestDiv; j <= largestDiv(i); j++) {
if (i % j === 0) {
continue loopi;
}
}
primeArr.push(i);
}
return primeArr;
}
function largestDiv (a) {
return Math.floor(Math.sqrt(a));
}
multiplyDict([1,13]);
it gives a dictionary of the requested array and the divisors of each element.
from there you can go on your own to check that your algorithm is doing the right job or you can check it here:
https://jsfiddle.net/cowCrazy/kr04mas7/
I hope it helps
It is true! The result of [1, 13] is 360360. and after this we have [1, 14].
14 = 2 * 7 and we now 360360 is dividable to 2 and 7 so the answer is 360360 again.
[1, 15]: 15 = 3 * 5 and result is same.
[1, 16]: result is 720720.
[1, 17]: result is: 12252240
[1, 18]: 18 = 2 * 9 and result is 12252240 same as 17
[1, 19]: for my computer this process is so heavy and can not do this. But in a strong machine it will work. I promise. But your code is not good in performance.
To find the LCM in N numbers.
It is Compatible with ES6, and consider that is there is no control for boundaries in case that we need to find for large numbers.
var a = [10, 40, 50, 7];
console.log(GetMinMultiple(a));
function GetMinMultiple(data) {
var maxOf = data.reduce((max, p) => p > max ? p : max, 0);
var incremental = maxOf;
var found = false;
do {
for (var j = 0; j < data.length; j++) {
if (maxOf % data[j] !== 0) {
maxOf += incremental;
break;
}
else {
if (j === data.length - 1) {
found = true;
break;
}
}
}
} while (!found);
return maxOf;
}
https://jsfiddle.net/djp30gfz/
Here is my solution in Typescript
function greatestCommonDivider(x: number, y: number): number {
if (y === 0) {
return x;
}
return greatestCommonDivider(y, x % y);
}
function singleLowestCommonMultiply(x: number, y: number): number {
return (x * y) / greatestCommonDivider(x, y);
}
function lowestCommonMultiply(...numbers: number[]): number {
/**
* For each number, get it's lowest common multiply with next number.
*
* Then using new number, compute new lowest common multiply
*/
return numbers.reduce((a, b) => {
return singleLowestCommonMultiply(a, b);
});
}
lowestCommonMultiply(2, 3); // Outputs 6
lowestCommonMultiply(2, 3, 5); // Outputs 30
Playground - click here
Related
I want to write a Generator for Fibonacci numbers in Javascript;
0,1,1,2,5,7,12..... (to make the sequence you have to add the last two numbers)
But I have this problem when I assign the the output.length to a variable the code is not working, if I write it down straight instead of "newNumber" the code down is however working, but I don't understand what is wrong with the first one. Is it something wrong with the place of the variables?
function fibonacciGenerator(n) {
var output = [];
var lastNumber = output[output.length - 1];
var nPrev = output[output.length - 2];
var newNumber = lastNumber + nPrev;
if (n === 1) {
output = [0];
} else if (n === 2) {
output = [0, 1];
} else {
output = [0, 1];
for (var i = 2; i < n; i++) {
output.push(newNumber);
}
}
return output
}
console.log(fibonacciGenerator(5));
function fibonacciGen(n) {
const output = [0, 1];
// Return an empty array if n is less than 1
if (n < 1) {
return [];
}
// If n is 1 or 2, we can return the array now
if (n <2) {
return output;
}
// Loop through the remaining numbers in the sequence
for (let i = 2; i < n; i++) {
// Calculate the next number in the sequence
let lastNumber = output[output.length - 1];
let nPrev = output[output.length - 2];
let newNumber = lastNumber + nPrev;
// Add the new number to the output array
output.push(newNumber);
}
// Return the output array
return output;
}
console.log(fibonacciGen(5));
you have to declare your logic of next term in loop because first time length of output is zero
function fibonacciGenerator (n) {
var output =[];
if (n < 1) {
return [];
}
if (n===1){
output=[0];
}
else if (n===2){
output=[0,1];
}
else{
output=[0,1];
for( var i = 2; i < n; i++){
var lastNumber=output[output.length-1];
var nPrev=output[output.length-2];
var newNumber=lastNumber+nPrev;
output.push(newNumber);
}
}
return output
}
function fib(n) {
const result = [0, 1];
for (var i = 2; i <= n; i++) {
const a = (i - 1);
const b = (i - 2);
result.push(a + b);
}
return result[n];
}
console.log(fib(8));
The output of the code above is 13. I don't understand the for loop part. In very first iteration i = 2, but after second iteration i = 3 so a = 2 and b = 1 and third iteration i = 4 so a = 3, b = 2, and so on... If it's going on final sequence will be :
[0, 1, 1, 3, 5, 7, 9, 11], which is incorrect. The correct sequence will be [0, 1, 1, 2, 3, 5, 8, 13]
You were not using the previous two numbers that are already in the array to > generate the new fibonacci number to be inserted into the array.
https://www.mathsisfun.com/numbers/fibonacci-sequence.html
Here I have used the sum of result[i-2] and result[i-1] to generate the new fibonacci number and pushed it into the array.
Also to generate n number of terms you need the condition to be i < n and not i <= n.
function fib(n) {
const result = [0, 1];
for (var i = 2; i < n; i++) {
result.push(result[i-2] + result[i-1]);
}
return result; // or result[n-1] if you want to get the nth term
}
console.log(fib(8));
Return result[n-1] if you want to get the nth term.
My solution for Fibonacci series:
const fibonacci = n =>
[...Array(n)].reduce(
(acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
[]
)
This function is incorrect. It cat be checked by just adding the console.log call just before the function return:
function fib(n) {
const result = [0, 1];
for (var i = 2; i <= n; i++) {
const a = (i - 1);
const b = (i - 2);
result.push(a + b);
}
console.log(result);
return result[n];
}
console.log(fib(7));
As you can see, the sequence is wrong and (for n = 7) the return value is too.
The possible change would be as following:
function fib(n) {
const result = [0, 1];
for (var i = 2; i <= n; i++) {
const a = result[i - 1];
const b = result[i - 2];
result.push(a + b);
}
console.log(result);
return result[n];
}
console.log(fib(8));
This is the "classical" Fibonacci numbers; if you really want to use the first number of 0, not 1, then you should return result[n-1], since array indexes start from zero.
One approach you could take for fibonacci sequence is recursion:
var fibonacci = {
getSequenceNumber: function(n) {
//base case to end recursive calls
if (n === 0 || n === 1) {
return this.cache[n];
}
//if we already have it in the cache, use it
if (this.cache[n]) {
return this.cache[n];
}
//calculate and store in the cache for future use
else {
//since the function calls itself it's called 'recursive'
this.cache[n] = this.getSequenceNumber(n - 2) + this.getSequenceNumber(n - 1);
}
return this.cache[n];
},
cache: {
0: 0,
1: 1
}
}
//find the 7th number in the fibbonacci function
console.log(fibonacci.getSequenceNumber(7));
//see all the values we cached (preventing extra work)
console.log(fibonacci.cache);
//if you want to output the entire sequence as an array:
console.log(Object.values(fibonacci.cache));
The code above is also an example of a dynamic programming approach. You can see that I am storing each result in a cache object the first time it is calculated by the getSequenceNumber method. This way, the second time that getSequenceNumber is asked to find a given input, it doesn't have to do any actual work - just grab the value from cache and return it! This is an optimization technique that can be applied to functions like this where you may have to find the value of a particular input multiple times.
const fib = n => {
const array = Array(n);
for (i = 0; i < array.length; i++) {
if (i > 1) {
array[i] = array[i - 1] + array[i - 2];
} else {
array[i] = 1;
}
}
return array;
}
console.log(fib(5))
What you are doing wrong is adding the iterator index (i), whereas what you need to do is add the element in the result at that index.
function fib(n) {
const result = [0, 1];
for (let i = 2; i <= n; i++) {
const a = result[(i - 1)];
const b = result[(i - 2)];
result.push(a + b);
}
console.log("Result Array: " + result);
return result[n];
}
console.log("Fibonacci Series element at 8: " + fib(8));
There are two issues with the logic:
Variables a and b currently refer to i - 1 and i - 2. Instead they should refer to the elements of result array, i.e. result[i - 1] and result[i - 2].
If you need 8th element of the array, you need to call result[7]. So the returned value should be result[n - 1] instead of result[n].
function fib(n) {
const result = [0, 1];
for (var i = 2; i < n; i++) {
const a = result[i - 1];
const b = result[i - 2];
result.push(a + b);
}
console.log(result);
return result[n - 1];
}
console.log(fib(8));
simple solution for Fibonacci series:
function fib(n){
var arr = [];
for(var i = 0; i <n; i++ ){
if(i == 0 || i == 1){
arr.push(i);
} else {
var a = arr[i - 1];
var b = arr[i - 2];
arr.push(a + b);
}
}
return arr
}
console.log(fib(8))
This is certainly one of those "more than one way to clean chicken" type situations, this JavaScript method below works for me.
function fibCalc(n) {
var myArr = [];
for (var i = 0; i < n; i++) {
if(i < 2) {
myArr.push(i);
} else {
myArr.push(myArr[i-2] + myArr[i-1]);
}
}
return myArr;
}
fibCalc(8);
When called as above, this produces [0,1,1,2,3,5,8,13]
It allows me to have a sequence of fib numbers based on n.
function fib(n) {
const result = [0];
if (n > 1) {
result.push(1);
for (var i = 2; i < n; i++) {
const a = result[result.length - 1]
const b = result[result.length - 2];
result.push(a + b);
}
}
console.log(result);
}
i came up with this solution to get the n index fibonacci value.
function findFac(n){
if (n===1)
{
return [0, 1];
}
else
{
var s = findFac(n - 1);
s.push(s[s.length - 1] + s[s.length - 2]);
return s;
}
}
function findFac0(n){
var vv1 = findFac(n);
return vv1[n-1];
}
console.log(findFac0(10));
Here, you have it, with few argument check, without using exception handling
function fibonacci(limit){
if(typeof limit != "number"){return "Please enter a natural number";}
if(limit <=0){
return "limit should be at least 1";
}
else if(limit == 1){
return [0];
}
else{
var series = [0, 1];
for(var num=1; num<=limit-2; num++){
series.push(series[series.length-1]+series[series.length-2]);
}
return series;
}
}
I came up with this solution.
function fibonacci(n) {
if (n == 0) {
return [0];
}
if ( n == 1) {
return [0, 1];
} else {
let fibo = fibonacci(n-1);
let nextElement = fibo [n-1] + fibo [n-2];
fibo.push(nextElement);
return fibo;
}
}
console.log(fibonacci(10));
function fibonacciGenerator (n) {
var output = [];
if(n===1){
output=[0];
}else if(n===2){
output=[0,1];
}else{
output=[0,1];
for(var i=2; i<n; i++){
output.push(output[output.length-2] + output[output.length-1]);
}
}
return output;
}
output = fibonacciGenerator();
console.log(output);
function fibonacci(end) {
if (isNaN(end) === false && typeof (end) === "number") {
var one = 0, res, two = 1;
for (var i = 0; i < end; ++i) {
res = one + two;
one = two;
two = res;
console.log(res);
}
} else {
console.error("One of the parameters is not correct!")
}
}
fibonacci(5);
var input = parseInt(prompt(""));
var a =0;
var b=1;
var x;
for(i=0;i<=input;i++){
document.write(a+"<br>")
x = a+b;
a =b;
b= x;
}
Given an array of integers, find the pair of adjacent elements that has the largest product and return that product.
and here is my code
function adjacentElementsProduct(inputArray) {
var arr = inputArray;
var x=0;
var y=0;
var p=0;
for(var i=0;i<arr.length;i++){
x=arr[i];
y=arr[i+1];
if(x*y>p){
p=x*y;
};
};
return p;
};
the problem is all the tests works fine but except the array with the negative product as it shown in the attached photo
can anyone help .. and thanks in advance
You could start with a really large negative value, instead of zero.
var p = -Infinity;
You are initializing the variable p to zero. That means any multiplication values smaller than that are not accepted. Rather set it to the smallest possible integer value:
var p = Number.MIN_SAFE_INTEGER;
function adjacentElementsProduct(inputArray) {
var arr = inputArray;
var x = 0;
var y = 0;
var p = Number.MIN_SAFE_INTEGER;
for (var i = 0; i < arr.length; i++) {
x = arr[i];
y = arr[i + 1];
if (x * y > p) {
p = x * y;
};
};
return p;
};
console.log(adjacentElementsProduct([-23, 4, -3, 8, -12]));
This is quite simple actually
function adjacentElementsProduct(inputArray) {
let max = -Infinity;
for (let i = 1; i < inputArray.length; i++) {
max = Math.max(inputArray[i] * inputArray[i - 1], max);
}
return max;
}
This is quite simple actually
const solution = (inputArray) => Math.max(...inputArray.slice(0, -1).map((n, index) => n * inputArray[index + 1]))
console.log(solution([3, 6, -2, -5, 7, 3]))
function solution(inputArray: number[]): number {
var max = -Infinity;
for(var i=0; i+1<inputArray.length; i++)
{
if(max<(inputArray[i]*inputArray[i+1])){
max=inputArray[i]*inputArray[i+1];
}
}
return max;
}
console.log(solution([2,3,6]))
I had the same problem at first, defining the first max as 0. Then i came up with this:
function solution(inputArray) {
let products = inputArray.map(function(x, index){
return inputArray[index+1] != undefined? x *inputArray[index+1] : -Infinity;
})
return Math.max(...products);
}
Problem:
Given an array of integers, find the pair of adjacent elements that has the largest product and return that product. #javascript #arraymethods
function solution(inputArray) {
let productsArr = []; // to hold the products of adjacent elements
let n = 0;
for (let i = 0; i < inputArray.length; i++) {
if (i < inputArray.length - 1)
{
productsArr[n] = inputArray[i] * inputArray[i + 1];
n++;
}
}
return productsArr.reduce((aggr, val) => Math.max(aggr, val)); // to find out the biggest product
}
Here's a very simple implementation without using any additional variables (actually less), and no special values. Just simple logic.
function adjacentElementsProduct(inputArray) {
var c =inputArray[0]*inputArray[1];
var p = c;
for(var i=1;i<inputArray.length;i++){
console.log(c);
var c=inputArray[i]*inputArray[i+1];
if(c > p){
p=c;
};
};
return p;
};
console.log("minimum product = " + adjacentElementsProduct([-23,4,-3,8,-12]));
What I did was, initialize a variable c (current product) with the product of first two elements of the array. And then I declared the variable p and initialize it to c. This way, all other products are compared to this product. Rest is simple.
Hope it helps. :)
you can try to initialize a integer as negative infinity value -math.inf and then use the python ternary operator var=true if condition else false to find the maximum value
code in python
def adjacentarray(a):
maximum=-math.inf
for i,in range(0,len(a)-1):
maximum=a[i]*a[i+1] if a[i]*a[i+1]>maximum else maximum
return maximum
code in javascript
function adjacentElementsProduct(a) {
var maximum=-Infinity;
for (var i=0;i<a.length-1;i++){
maximum= a[i]*a[i+1]>maximum?a[i]*a[i+1]:maximum;
}
return maximum;
}
function solution(inputArray) {
let first, second, sum = []
inputArray.map((arr,index)=>{
first = arr;
second = inputArray[index+1]
if(second == undefined){
return second
}
return sum.push(first * second)
})
let last = sum.sort().reduce((pre,next)=> {
return pre > next ? pre : next
})
return last;
}
//Kotlin
fun solution(inputArray: MutableList<Int>): Int {
var result: Int = Int.MIN_VALUE
for (i in 0..inputArray.size - 2) {
if (inputArray[i] * inputArray[i + 1] > result)
result = inputArray[i] * inputArray[i + 1]
}
return result
}
import 'dart:math';
int solution(List<int> inputArray) {
//assumption for highest number
int highestNumber = inputArray[0] * inputArray[1] ;
//we'll go through the array to campare the highestNumber
//with next index
for(var i = 1 ; i < inputArray.length ; i++){
highestNumber = max(highestNumber, inputArray[i] * inputArray[i - 1]);
}
return highestNumber;
}
In Javascript, you could use the reduce method from an array to avoid iterating in a for loop, just like this.
function solution(inputArray) {
let maxProd = []
inputArray.reduce((accumulator, currentValue) => {
maxProd.push(accumulator*currentValue)
return currentValue
},
);
return Math.max(...maxProd)
}
Once you have in the maxProd array the products, you use the spread operator to get the numbers and using Math.max() you get the largest
python solution
You can make a loop from 1 to end of your list and do the following arithmetic operations
def solution(inputArray):
list1 =[]
for i in range(1,len(inputArray)):
list1.append(inputArray[i]*inputArray[i-1])
return max(list1)
Here is a solution in PHP that is quite simple.
function solution($inputArray) {
$largest = null;
$pos = null;
for($i = 0; $i < count($inputArray) -1; $i++){
$pos = ($inputArray[$i] * $inputArray[$i+1]);
if($largest < $pos){
$largest = $pos;
}
}
return $largest ?? 0;
}
You can try to create a new array of length (arr.length-1) inside the function and append the products of adjacent numbers to this new array. Then find the largest number in the array and return it. This will solve the problem with negative product.
function adjacentElementsProduct(inputArray) {
var arr = inputArray;
var prodArr[];
var p;
for (var i = 0; i < arr.length-1; i++) {
prodArr[i] = arr[i]*arr[i+1];
};
for (j=prodArr.length; j--){
if (prodArr[j] > p) {
p = prodArr[j];
};
return p;
};
console.log(adjacentElementsProduct([-23, 4, -3, 8, -12]));
The var p which saves the max product should be initialized as small as possible instead of a 0. So that when the product is negative, it will still meet the if condition and save the value.
Here is a C# solution:
static void Main(string[] args)
{
int[] arr = { 1, -4, 3, -6, -7, 0 };
Console.WriteLine(FindMaxProduct(arr));
Console.ReadKey();
}
static int FindMaxProduct(int[] arr) {
int currentProduct = 0;
int maxProduct = int.MinValue;
int a=0, b = 0;
for (int i = 0, j = i + 1; i < arr.Length - 1 && j < arr.Length; i++, j++)
{
currentProduct = arr[i] * arr[j];
if (currentProduct>maxProduct) {
a = arr[i];
b = arr[j];
maxProduct = currentProduct;
}
}
Console.WriteLine("The max product is {0}, the two nums are {1} and {2}.",maxProduct,a,b);
return maxProduct;
}
function solution(inputArray) {
let f, s, arr = []
for(let i=0; i<inputArray.length; i++){
f = inputArray[i]
s = inputArray[i+1]
arr.push(f*s)
}
let max = arr.sort((a, b) => b - a)
return max[0]
}
console.log(solution([3, 6, -2, -5, 7, 3]))
This should help, wrote it in python. Concept: Pass an empty list, for every consecutive product keep storing it in the list. Then just return the max value.
def consecutive_product_max(a):
lst2 = []
for i in range(0, len(a)-1):
x = a[i] * a[i+1]
lst2.append(x)
return max(lst2)
I was doing a test that required an algorithm for Binary Tomography. A set of 38 test values are supplied that test correctness, but there is also a time limit of 1 CPU sec to complete all the tests. The problem is as follows:
Output “Yes” if there exists an m-by-n matrix A, with each element either being 0 or 1, such that
Otherwise output “No”.
For each test, 2 arrays are provided:
r (the sum of each row in the matrix)
c (the sum of each column in the matrix)
In the equation:
m is the length of the r array, where 1 <= m
n is the length of the c array, where n <= 1000
ri is an element of r, where 0 <= ri <= n
cj is an element of c, where 0 <= cj <= m
A "Yes" example
m = 3;
n = 4;
r = [2, 3, 2];
c = [1, 1, 3, 2];
A "No" example
m = 3;
n = 3;
r = [0, 0, 3];
c = [0, 0, 3];
I have a solution that appears to give correct answers, however it only manages 12 / 38 tests before the 1 second of CPU time is exceeded.
I originally wrote the code in ES5 and then went back and converted to to ES3 to try and get more performance out of it. (originally managed 9 tests as ES5). There doesn't seem a great deal left that I can do to the current algorithm to improve the performance (unless I am mistaken). This leads me to believe that my algorithm is at fault an that there must be a faster algorithm for doing this. I did a ton of reading trying to find one and ended up with a headache :)
So I'm turning to the community to see if anyone can suggest a faster algorithm than I am currently using.
'use strict';
const ZEROS = (function (seed) {
let string = seed;
for (let i = 0; i < 19; i += 1) {
string += seed;
}
return string;
}('00000000000000000000000000000000000000000000000000'));
const ZEROSLEN = ZEROS.length;
const permutate = function (n, ri) {
const result = [];
const memoize = {};
let count = 0;
do {
const bin = count.toString(2);
if (ZEROSLEN + bin.length > ZEROSLEN + n) {
break;
}
if (!memoize[bin] && (bin.split('1').length - 1) === ri) {
const string = (ZEROS + bin).slice(-n);
const sLen = string.length;
const perm = new Array(sLen);
for (let i = sLen - 1; i >= 0; i -= 1) {
perm[i] = +string[i];
}
memoize[bin] = result.push(perm);
}
count += 1;
} while (count);
return result;
};
const getMatrixSum = function (n, matrix) {
const mLength = matrix.length;
const rows = new Array(mLength);
const a = new Array(n);
const last = mLength - 1;
for (let x = n - 1; x >= 0; x -= 1) {
for (let y = last; y >= 0; y -= 1) {
rows[y] = matrix[y][x];
}
let sum = 0;
for (let i = rows.length - 1; i >= 0; i -= 1) {
sum += rows[i];
}
a[x] = sum;
}
return a;
};
const isEqual = function (a, b) {
const length = a.length;
if (length !== b.length) {
return false;
}
for (let i = length - 1; i >= 0; i -= 1) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
};
const addRow = function (i, prev, r, c, result) {
if (result) {
return result;
}
const n = c.length;
const ri = r[i];
if (ri < 0 || ri > n) {
throw new RangeError('ri out of range');
}
const p = permutate(n, ri);
const m = r.length;
const rsLast = m - 1;
const nextI = i + 1;
for (let x = p.length - 1; x >= 0; x -= 1) {
const permutation = p[x];
const next = prev.slice();
next.push(permutation);
const sums = getMatrixSum(n, next);
if (i < rsLast) {
let memo = 0;
for (let j = sums.length - 1; j >= 0; j -= 1) {
if (sums[j] > c[j]) {
memo += 1;
}
}
if (!memo && addRow(nextI, next, r, c, result)) {
return true;
}
} else if (isEqual(sums, c)) {
return true;
}
}
return false;
};
const isSolvable = function (r, c) {
const m = r.length;
const n = c.length;
if (m < 1 || n > 1000) {
throw new Error('Bad data');
}
for (let j = n; j >= 0; j -= 1) {
const cj = c[j];
if (cj < 0 || cj > m) {
throw new RangeError('cj out of range');
}
}
return addRow(0, [], r, c, false) ? 'Yes' : 'No';
};
console.log(isSolvable([2, 3, 2], [1, 1, 3, 2]));
console.log(isSolvable([0, 0, 3], [0, 0, 3]));
It may be worth noting that the tests are being run on SpiderMonkey version JavaScript-C24.2.0
Refs:
https://en.wikipedia.org/wiki/Discrete_tomography
https://open.kattis.com/problems/tomography
Since permutations yield to brute force, they should be the last resort when developing algorithms similar to this one. Most of the time they are not needed.
As i have commented above, I have a feeling that one strategy could be first sorting the r and c arrays descending and start with the bigger ones. I haven't had time to implemented a JS code to work out this, so I haven't had a chance to test thoroughly. Please have a look and if you discover a flaw please mention.
In the below visual representation of the algorithm we try r = [1,3,1,3] and c = [3,2,1,2]. X denotes an occupied cell and a red dot denotes an untouchable cell while the empty ones are obviously the free cells. So in the real algorithm to represent a cell we need a data type like {value: false, avail: false} for a red dot while {value: false, avail: true} would mean a free space. Or to save space and speed you may use a data type like 0b00 for red dot, 0b01 for free space and 0b1X for occupied (X here means don't care) cells.
Note: It's worth mentioning Step 3 where we process c[0]. After we insert the three Xs we have to check the rows occupied by the Xs to update the status of the empty cells in those rows. In this case for r[2], all empty cells become untouchable.
Edit:
Well.. OK since we don't need to construct the solution in a 2D array like structure but only need an answer on wheather the supplied data is meaningful or not, I have come up with another and simpler idea which is essentially based on the above approach. I really don't think it can get any faster than this. It solves a 999 by 1000 board in like 50ms.
Lets get into it.
The input is r = [2, 3, 2]; c = [1, 1, 3, 2]; However one important condition here is both c and r arrays should sum up to the same number. We can simply check this at the beginning of our code or leave it, go through the following steps and if they pass check only if c is full of 0s. The following code prefers the latter approach.
Sort r descending so; r = [3, 2, 2]; c = [1, 1, 3, 2];
Try reducing r[0] (3 in the first case) many non-zero elements of c by 1. Now c becomes [0, 0, 2, 2]. If it fails then try no more and return false.
Now that we have finished with row r[0], recursivelly call function with r = [2, 2]; c = [0, 0, 2, 2]; while r.length is bigger than 0 and the bool argument b is true. Next call will be r = [2]; c = [0, 0, 1, 1]; and finally r = []; c = [0, 0, 0, 0];
If finally a recursive call with empty r is invoked then check b is true and all items of c are 0. (b && cs.every(n => !n)).
I believe this is just fine but as i don't have your test cases it's for you to try. I am sure it will pass the time test though. Here is the code in it's simplest. Here i am testing rs = [7,3,5,4,6,2,8] and cs = [7,1,6,3,4,5,2,7]. It looks like;
71634527
7 x xxxxxx
3 x x x
5 x x xx x
4 x x x x
6 x xxxx x
2 x x
8 xxxxxxxx
function nonogram(rs,cs){
function runner(rs,cs, b = true){//console.log(rs,cs,b)
return b && rs.length ? runner(rs.slice(1), // rows argument
cs.map(e => rs[0] ? e ? (b = !--rs[0], e-1) // cols argument
: e
: e),
b) // bool argument
: b && cs.every(n => !n);
}
return runner(rs.sort((a,b) => b-a), cs);
}
var rs = [7,3,5,4,6,2,8],
cs = [7,1,6,3,4,5,2,7],
result;
console.time("test");
result = nonogram(rs,cs);
console.timeEnd("test");
console.log(result);
I didn't have this ready for my test, but I found a far more efficient algorithm after the event.
'use strict';
const sortNumber = function (a, b) {
return b - a;
};
const isSolvable = function (r, c) {
const m = r.length;
const n = c.length;
if (m < 1 || n > 1000) {
throw new Error('Bad data');
}
for (let j = n; j >= 0; j -= 1) {
const cj = c[j];
if (cj < 0 || cj > m) {
throw new RangeError('cj out of range');
}
}
while (r.length) {
c.sort(sortNumber);
const ri = r.pop();
if (ri < 0 || ri > n) {
throw new RangeError('ri out of range');
}
if (ri) {
if (!c[ri - 1]) {
return 'No';
}
for (let j = ri - 1; j >= 0; j -= 1) {
c[j] -= 1;
}
}
}
for (let j = n - 1; j >= 0; j -= 1) {
if (c[j]) {
return 'No';
}
}
return 'Yes';
};
console.log(isSolvable([2, 3, 2], [1, 1, 3, 2]));
console.log(isSolvable([0, 0, 3], [0, 0, 3]));
I've finished this challenge from Coderbyte, but inelegantly:
Have the function PrimeChecker(num) take num and return 1 if any
arrangement of num comes out to be a prime number, otherwise return 0.
For example: if num is 910, the output should be 1 because 910 can be
arranged into 109 or 019, both of which are primes.
My solution works by producing an array of all possible permutations of the digits in the num argument, then scanning it for primes:
function PrimeChecker(num) {
// Accounting for 1 not being a prime number by definition
if (num == 1) {
return 0;
}
// Defining an empty array into which all permutations of num will be put
var resultsArray = [];
// Breaking num into an array of single-character strings
var unchangedArray = num.toString().split('');
// Function to push all permutations of num into resultsArray using recursion
function getAllCombos (array, count) {
if (count === num.toString().length) {
return;
}
else {
for (var i = 0; i < array.length; i++) {
var temp = array[count];
array[count] = array[i];
array[i] = temp;
resultsArray.push(array.join(''));
}
return getAllCombos(array, count+1) || getAllCombos(unchangedArray, count+1);
}
}
getAllCombos(unchangedArray, 0);
// Converting the results from strings to numbers and checking for primes
var numArr = [];
resultsArray.forEach(function(val, indx) {
return numArr[indx] = Number(val);
});
for (var i = 0; i < numArr.length; i++) {
var prime = 1;
for (var j = 2; j < numArr[i]; j++) {
if (numArr[i] % j == 0) {
prime = 0;
}
}
if (prime == 1) {
return prime;
}
}
return 0;
}
The problem is that the array of permutations of the num argument which I'm producing is full of duplicates.. I feel like this can be done more efficiently.
For example, running PrimeChecker(123) results in a permutations array of 20 entries, when there only need be 6.
Does anyone have an idea of how to do this more efficiently?
This is how I would do it:
var permute = (function () {
return permute;
function permute(list) {
return list.length ?
list.reduce(permutate, []) :
[[]];
}
function permutate(permutations, item, index, list) {
return permutations.concat(permute(
list.slice(0, index).concat(
list.slice(index + 1)))
.map(concat, [item]));
}
function concat(list) {
return this.concat(list);
}
}());
function isPrime(n) {
for (var i = 2, m = Math.sqrt(n); i <= m; i++)
if (n % i === 0) return false;
return true;
}
function PrimeChecker(num) {
return permute(num.toString(10).split("")).some(function (xs) {
return isPrime(parseInt(xs.join(""), 10));
}) ? 1 : 0;
}
alert(PrimeChecker(910));
Here's the explanation of the algorithm for finding the permutations of the elements of an array.
Hope that helps.