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]));
Related
Wrote a solution for Combination Sum IV using Top-Down DP JavaScript solution which is giving incorrect results, any pointers what could have gone wrong
Here is problem description
Input: nums = [1,2,3], target = 4
Output: 7
Explanation:
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
Note that different sequences are counted as different combinations.
Here is the solution in javascript
var combinationSum4 = function(N, T) {
//w/ Top Down DP:
// Create dp array
const dp = Array(T + 1).fill(0)
// Set default
dp[0] = 1
// Loop until we hit target
for (let i = 1; i <= T; i++) {
// Loop through all possible nums
for (let j = 0; j < N.length; j++)
if (N[j] <= i) {
dp[i] += dp[i - N[j]]
}
}
return dp[T]
};
let N = [1, 2, 3]
let T = 4
console.log(combinationSum4(N, T))
After adding console logs,output shows 52
var combinationSum4 = function(N, T) {
//w/ Top Down DP:
// Create dp array
const dp = Array(T+1).fill(0)
// Set default
dp[0] = 1
// Loop until we hit target
for(let i = 1; i <= T;i++) {
// Loop through all possible nums
for(let j = 0; j < N.length; j++)
if(N[j] <= i)
{
dp[i] += dp[i- N[j]]
console.log(` i: ${JSON.stringify(i)}`)
console.log(`dp i: ${JSON.stringify(dp[i])}`)
console.log(`dp at dp[i- N[j]]: ${JSON.stringify(dp[i- N[j]])}`)
console.log(`i- N[j]: ${JSON.stringify(i- N[j])}`)
console.log(` N[j]: ${JSON.stringify(N[j])}`)
console.log(` Actual code: ${JSON.stringify(dp[i] += dp[i- N[j]])}`)
}
}
return dp[T]
};
let N = [1,2,3]
let T = 4
console.log(combinationSum4(N,T))
Also how i can see all the combinations in above code
Output shown is 52 whereas expected is 7
Your help is highly appreciated
Regards
Carolyn
Given an array N which contains at least 5 items, I want to find 2 numbers(P and Q) in which 0 < P < Q < N - 1.
Suppose we have the following array:
const N = [1, 9, 4, 5, 8];
if P = 1 , Q = 2 , the cost will be N[P] + N[Q] = N[1] + N[2] = 9 + 4 = 13
if P = 1, Q = 3 , the cost will be N[P] + N[Q] = N[1] + N[3] = 9 + 5 = 14
if P = 2, Q = 3 , the cost will be N[P] + N[Q] = N[2] + N[3] = 4 + 5 = 9
From here the combination which gives the minimum cost is P = 2 and Q = 3.
Here is the solution that I found and I am looking for your help if I can improve its time complexity:
function solution(N) {
// since 0 < P < Q < N - 1
const sliced = N.slice(1, N.length - 1);
const sorted = sliced.sort((a, b) => a - b);
// the minimum should be from the start since we have sorted the array
const P = 0;
const Q = 1;
return getCost(P, Q, sorted);
}
function getCost(P, Q, N) {
return N[P] + N[Q];
}
// output should be 9
console.log(solution([1, 9, 4, 5, 8]))
In a best-case scenario it's 0(n log(n)) because of the sort, but I am wondering if we can improve it to O(n) for example.
Thanks for your help
function twoSmallest(arr) {
let [first, second] = [arr[1], arr[2]]
for (let i = 3; i < arr.length - 1; i++) {
const el = arr[i]
if (el < first && el < second) {
[first, second] = [Math.min(first, second), el]
} else if (el < first) {
[first, second] = [second, el]
} else if (el < second) {
second = el
}
}
return first + second
}
This is an O(n) time and O(1) space solution. It also makes sure that the element with the smaller index is kept in first for the case where you need to use the indices and it is of interest for some reason.
The algorithm is clear, IMO, but the JS code is probably not the best implementation. I haven't written JS for some time.
What do you think of this solution?
function solution([_, ...n]) {
n.pop()
n.sort((a, b) => a - b);
return n[0] + n[1];
}
// output should be 9
console.log(solution([1, 9, 4, 5, 8]))
The logic is the same that you outlined - only using some other approach that JS offers.
I'm pretty sure this is O(n):
const solution = (arr) => {
// find smallest that's not at either end
let idx = 1;
let P = arr[1];
for(let i = 2; i < arr.length-1; i++) {
if(arr[i] < P) {
idx = i;
P = arr[i];
}
}
// find second smallest that's not at either end
let Q = Infinity;
for(let i = 1; i < arr.length-1; i++) {
if(i == idx) continue;
if(arr[i] < Q) Q = arr[i];
}
return P + Q;
}
Here is the fastest way to find k smallest numbers in a list with Python. The rest is trivial
fastest method of getting k smallest numbers in unsorted list of size N in python?
I am learning about heaps and I wanted to implement the heap sort algorithm in Javascript using MinHeap.
The issue is that I keep getting a non-sorted array.
I even tried to just translate a working algorithm from C++ to Javascript.
Orginal algorithm link: https://www.geeksforgeeks.org/heap-sort-for-decreasing-order-using-min-heap/
C++:
// To heapify a subtree rooted with node i which is
// an index in arr[]. n is size of heap
void heapify(int arr[], int n, int i)
{
int smallest = i; // Initialize smalles as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
// If left child is smaller than root
if (l < n && arr[l] < arr[smallest])
smallest = l;
// If right child is smaller than smallest so far
if (r < n && arr[r] < arr[smallest])
smallest = r;
// If smallest is not root
if (smallest != i) {
swap(arr[i], arr[smallest]);
// Recursively heapify the affected sub-tree
heapify(arr, n, smallest);
}
}
// main function to do heap sort
void heapSort(int arr[], int n)
{
// Build heap (rearrange array)
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// One by one extract an element from heap
for (int i = n - 1; i >= 0; i--) {
// Move current root to end
swap(arr[0], arr[i]);
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
Javascipt (translated code):
function swap(arr, i, j){
const c = arr[i];
arr[i] = arr[j];
arr[j] = c;
}
function heapify(arr, n, i)
{
let smallest = i; // Initialize smalles as root
let l = 2 * i + 1; // left = 2*i + 1
let r = 2 * i + 2; // right = 2*i + 2
// If left child is smaller than root
if (l < n && arr[l] < arr[smallest])
smallest = l;
// If right child is smaller than smallest so far
if (r < n && arr[r] < arr[smallest])
smallest = r;
// If smallest is not root
if (smallest != i) {
swap(arr[i], arr[smallest]);
// Recursively heapify the affected sub-tree
heapify(arr, n, smallest);
}
}
// main function to do heap sort
function heapSort(arr, n)
{
// Build heap (rearrange array)
for (let i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// One by one extract an element from heap
for (let i = n - 1; i >= 0; i--) {
// Move current root to end
swap(arr[0], arr[i]);
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
when I try with this array arr = [1,2,7,3,5], the heapSort algorithm returns this table [ 1, 2, 7, 3, 5 ];
Can you please help me figure out what's wrong with the JS implementation?
thank you in advance!
This code should go fine:
const heapify = (arr, length, i) => {
let largest = i
const left = i * 2 + 1
const right = left + 1
if (left < length && arr[left] > arr[largest]) {
largest = left
}
if (right < length && arr[right] > arr[largest]) {
largest = right
}
if (largest !== i) {
[arr[i], arr[largest]] = [arr[largest], arr[i]]
heapify(arr, length, largest)
}
return arr
}
const heapSort = arr => {
const length = arr.length
let i = Math.floor(length / 2 - 1)
let k = length - 1
while (i >= 0) {
heapify(arr, length, i)
i--
}
while (k >= 0) {
[arr[0], arr[k]] = [arr[k], arr[0]]
heapify(arr, k, 0)
k--
}
return arr
}
const arr = [4, 6, 3, 2, 9];
sortedArr = heapSort(arr);
console.log("Sorted array is \n", sortedArr)
I took it from here. Take a look at the post if you are more interested in how it's implemented. It's very well explained.
UPDATE
Ok so, about your code, I see exactly 2 problems:
You are incorrectly using the "swap" function. Just change swap(arr[i], arr[smallest] by swap(arr, i, smallest); and swap(arr[0], arr[i]) by swap(arr, 0, i). Also, if you want to use the latest ES6 features you can swap elements in an array without implementing that "swap" function, just like this: [arr[0], arr[2]] = [arr[2], arr[0]] (this will swap the element at position 0 with the element at position 2). This is called destructuring assignment.
In the first for loop in your "heapSort" function, initialize i variable to an integer (notice that n / 2 could be a float). You can do it like this: let i = Math.floor(n / 2 - 1).
Here I leave you the fixed code. I've executed it by myself and it works:
function swap(arr, i, j){
const c = arr[i];
arr[i] = arr[j];
arr[j] = c;
}
function heapify(arr, n, i)
{
let smallest = i; // Initialize smallest as root
let l = 2 * i + 1; // left = 2*i + 1
let r = 2 * i + 2; // right = 2*i + 2
// If left child is smaller than root
if (l < n && arr[l] < arr[smallest])
smallest = l;
// If right child is smaller than smallest so far
if (r < n && arr[r] < arr[smallest])
smallest = r;
// If smallest is not root
if (smallest != i) {
swap(arr, i, smallest);
// Recursively heapify the affected sub-tree
heapify(arr, n, smallest);
}
}
// main function to do heap sort
function heapSort(arr, n)
{
// Build heap (rearrange array)
for (let i = Math.floor(n / 2 - 1); i >= 0; i--)
heapify(arr, n, i);
// One by one extract an element from heap
for (let i = n - 1; i >= 0; i--) {
// Move current root to end
swap(arr, 0, i);
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
const arr = [4, 6, 3, 2, 9];
heapSort(arr, arr.length);
console.log("Sorted array is \n", arr)
Here is my version of heapsort.
This is non-recursive solution and modifies the original array.
function swap(arr, i, j) {
const tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
function heapify(arr, start = 0) {
for(let i = start;i < arr.length; i++) {
let j = i;
let root = start + Math.floor((j-start)/2);
while(( root >= start ) && (arr[root] < arr[j])) {
swap(arr, root, j);
j = root;
root = start + Math.floor((j-start)/2);
}
}
}
function heapSort(arr) {
for(let i = 0; i < arr.length;i++)
heapify(arr, i);
}
const arr = [1,2,8000,3,4,5,-1,200000,8000,-1,20000];
heapSort(arr);
console.log(arr);
const HeapSort = (arg) => {
const Income_arr = [...arg];
const Output_arr = [];
const InnerSort = () => {
const length = Income_arr.length;
for (let i = 0; i < Income_arr.length - 1; i++) {
let max = i;
const left = i + 1;
const right = i + 2;
// will change '>' or '<' depends on which order we want, like either descending or ascending order
if (i <= length && Income_arr[i] > Income_arr[left]) {
// swapping the array
[Income_arr[i], Income_arr[left]] = [Income_arr[left], Income_arr[i]];
}
if (i <= length && Income_arr[i] > Income_arr[right]) {
// swapping the array
[Income_arr[i], Income_arr[right]] = [Income_arr[right], Income_arr[i]];
}
}
Output_arr.push(Income_arr.shift()); // Add the largest Number in output_arr & remove the largest Number
return Income_arr;
};
for (let i = arg.length - 1; i >= 0; i--) {
// Run untill array length ends
InnerSort(); // To Find the largest number
}
console.log(Output_arr)
return Output_arr;
};
HeapSort([16, 20, 99, 34, 17, 15]);
HeapSort([16, 20, -99, 34, 17, 15]);
HeapSort([4, 20, 9, 34, 2, 15]);
const HeapSort = (arg) => {
const Income_arr = [...arg];
const Output_arr = [];
const InnerSort = () => {
const length = Income_arr.length;
for (let i = 0; i < Income_arr.length - 1; i++) {
let max = i;
const left = i + 1;
const right = i + 2;
// will change '>' or '<' depends on which order we want, like either descending or ascending order
if (i <= length && Income_arr[i] > Income_arr[left]) {
// swapping the array
[Income_arr[i], Income_arr[left]] = [Income_arr[left], Income_arr[i]];
}
if (i <= length && Income_arr[i] > Income_arr[right]) {
// swapping the array
[Income_arr[i], Income_arr[right]] = [Income_arr[right], Income_arr[i]];
}
}
Output_arr.push(Income_arr[length - 1]); // Add the largest Number in output_arr
Income_arr.pop(); // Remove the largest Number
return Income_arr;
};
for (let i = arg.length - 1; i >= 0; i--) {
// Run untill array length ends
InnerSort(); // To Find the largest number
}
console.log(Output_arr)
return Output_arr;
};
HeapSort([16, 20, 99, 34, 17, 15]);
HeapSort([16, 20, -99, 34, 17, 15]);
HeapSort([4, 20, 9, 34, 2, 15]);
I'm trying to solve a basic problem in Hackerearth Given an array A of size N, you need to find the number of ordered pairs (i,j) such that i < j and A[i] > A[j].
I was able to find out an idea actually implemented it by having a global variable. But having a global value is not a good practice, hence I tried to pass it as parameter and I couldn't able to solve it. Am stuck with keeping an already returned value and adding an updated value to it.
// let ans = 0;
let mergeSort = (left, right, arr, ans) => {
let i = 0,
j = 0,
k = 0;
let leftLen = left.length,
rightLen = right.length;
while (i < leftLen && j < rightLen) {
if (left[i] <= right[j]) {
arr[k] = left[i];
i++;
} else {
arr[k] = right[j];
ans += leftLen - i;
j++;
}
k++;
}
while (i < leftLen) {
arr[k] = left[i];
i++;
k++;
}
while (j < rightLen) {
arr[k] = right[j];
j++;
k++;
}
return { arr, ans };
};
let divideArray = (arr, ans) => {
if (arr.length < 2) return { arr, ans };
let N = arr.length;
let mid = Math.round(N / 2);
let left = arr.slice(0, mid);
let right = arr.slice(mid, N);
ans = ans;
divideArray(left, ans);
divideArray(right, ans);
let blabla = mergeSort(left, right, arr, ans);
return blabla;
};
let merge = (arr, ans) => {
let res = divideArray(arr, ans);
return res;
};
function main(input) {
let arr = [1, 4, 3, 2, 5];
let ans = 0;
let output = merge(arr, ans);
console.log('Final', output);
}
main();
In mergeSort function When the input of the left array is [1,4] and the right array is [3] the ans will be updated as 1, also when the left array is [1,3,4] and right is [2,5] the ans will be updated as 2. I would like to add both this ans values and return it as 3. But somewhere am making a mistake while returning. Any help will be appreciated.
JsFiddle
EDIT:
Please note that am trying to achieve it via MergeSort and recursion i know in lot of other ways i can solve this problem for instance i have clearly mentioned i had solved it by having a global variable,which is not a good practice so please provide me a solution only via recursion and merge sort
There is no need to pass an inversion count to divideArray(), it only needs to return a sub_count = left_count + right_count + merged_count. The sub_counts originate from each instance of merging and will be accumulated as recursion returns sub-counts back up the call chain to produce a total_count.
Example of an optimized top down merge sort updated to return an inversion count. A helper function (mergesort()) does a one time allocation of an auxiliary array (aux). To avoid unneeded copying of data, two mutually recursive functions are used, sortarrtoarr() sorts data from arr[] back to arr[], while sortarrtoaux() sorts data from arr[] to aux[]. Each of the mutually recursive functions calls the other in order to change the direction of merge based on the level of recursion.
function merge(arr, aux, bgn, mid, end) {
var i = bgn;
var j = mid;
var k = bgn;
var cnt = 0; // count of inversions
while(true){
if(arr[i] <= arr[j]){ // if left element <= right element
aux[k++] = arr[i++]; // copy left element
if(i < mid) // if not end of left run
continue; // continue back to while
do // else copy rest of right run
aux[k++] = arr[j++]; // and break
while(j < end);
break;
} else { // else left element > right element
cnt += mid - i; // arr.slice(i,mid) is > arr[j]
aux[k++] = arr[j++]; // copy right element
if(j < end) // if not end of right run
continue; // continue back to while
do // else copy rest of left run
aux[k++] = arr[i++]; // and break
while(i < mid);
break;
}
}
return cnt; // return inversion count
}
// sort from arr[] to aux[]
function sortarrtoaux(arr, aux, bgn, end) {
if ((end-bgn) < 2){ // if only 1 element
aux[bgn] = arr[bgn]; // copy it to aux
return 0; // return inversion count == 0
}
var cnt = 0; // inversion count = 0
var mid = Math.floor(bgn + (end - bgn) / 2);
cnt += sortarrtoarr(arr, aux, bgn, mid); // sort left arr back to arr
cnt += sortarrtoarr(arr, aux, mid, end); // sort right arr back to arr
cnt += merge(arr, aux, bgn, mid, end); // merge arr to aux
return cnt; // return inversion count
}
// sort from arr[] back to arr[]
function sortarrtoarr(arr, aux, bgn, end) {
if ((end-bgn) < 2) // if only 1 element
return 0; // return inversion count == 0
var cnt = 0; // inversion count = 0
var mid = Math.floor(bgn + (end - bgn) / 2);
cnt += sortarrtoaux(arr, aux, bgn, mid); // sort left arr to aux
cnt += sortarrtoaux(arr, aux, mid, end); // sort right arr to aux
cnt += merge(aux, arr, bgn, mid, end); // merge aux to arr
return cnt; // return inversion count
}
// entry function for mergesort
function mergesort(arr) {
if(arr.length < 2) // if less than 2 elements
return 0; // return inversion count == 0
var aux = new Array(arr.length); // allocate aux[] and start merge sort
return sortarrtoarr(arr, aux, 0, arr.length);
}
var arr = [8, 6, 7, 5, 3, 0, 9];
var cnt = mergesort(arr);
console.log(cnt);
for (i = 1; i < arr.length; i++) {
if(arr[i-1] > arr[i]){
console.log('error');
break;
}
}
Scott's answer offers a functional approach. Generators, function* below, offer another capable and flexible way of encoding this kind of problem -
const descendingPairs = function* (a = [])
{ for (const i of range(0, a.length)) // for all (0 <= i < a.length)
for (const j of range(0, a.length)) // for all (0 <= i < a.length)
if (i < j) // such that i < j
if (a[i] > a[j]) // and a[i] > a[j]
yield [ a[i], a[j] ] // output descending pair
}
We can optimise this by using i as the input for the j range's start -
const descendingPairs = function* (a = [])
{ for (const i of range(0, a.length)) // for all (0 < i < a.length)
for (const j of range(i + 1, a.length)) // for all (i < j < a.length)
if (a[i] > a[j]) // such that a[i] > a[j]
yield [ a[i], a[j] ] // output descending pair
}
range is nicely-encoded using a generator as well -
const range = function* (start = 0, stop = 0)
{ for (let x = start; x < stop; x++)
yield x
}
We can output the results of each descending pair -
const input =
[ 1, 4, 3, 2, 5 ]
for (const pair of descendingPairs(input))
console.log(pair)
// [ 4, 3 ]
// [ 4, 2 ]
// [ 3, 2 ]
Or we can collect all pairs into an array -
Array.from(descendingPairs(input))
// => [ [ 4, 3 ], [ 4, 2 ], [ 3, 2 ] ]
Or we can simply count them -
Array.from(descendingPairs(input)).length
// => 3
Expand the snippet below to verify the results in your own browser -
const range = function* (start = 0, stop = 0)
{ for (let x = start; x < stop; x++)
yield x
}
const descendingPairs = function* (a = [])
{ for (const i of range(0, a.length))
for (const j of range(i, a.length))
if (a[i] > a[j])
yield [ a[i], a[j] ]
}
const input =
[ 1, 4, 3, 2, 5 ]
console.log(Array.from(descendingPairs(input)))
// [ [ 4, 3 ], [ 4, 2 ], [ 3, 2 ] ]
console.log(Array.from(descendingPairs(input)).length)
// 3
I'm having a hard time figuring why you are writing this with code that's all about a mergesort. It seems to me that all you need to do is to generate the index pairs where j > i (a fairly easy task) and then count those for which A[i] > A[j]. Recursion is a fine way (though by no means the only easy way) to create those index pairs. The rest is a filter/length combination or a reduce.
Here's one variation:
const countDescendingPairs = (xs) =>
xs .map ((x, i) => xs .slice (i + 1) .filter(y => x > y) .length)
.reduce ((a, b) => a + b, 0)
console .log (
countDescendingPairs ([8, 6, 7, 5, 3, 0, 9])
)
But there are many simple alternatives.
And if you wanted to retrieve those pairs, it's a straightforward modification:
const descendingPairs = (xs) =>
xs .flatMap (
(x, i) =>
xs .slice (i + 1)
.filter (y => x > y)
.map ((y) => ({x, y}))
)
console .log (
descendingPairs ([8, 6, 7, 5, 3, 0, 9])
)
Updated to add flatMap and to remove the incorrect indices from the second version. (You can't filter, then expect the old index to still work!)
https://codepen.io/Santhoshsanz/pen/dybedgm?editors=1112
// let ans = 0;
let mergeSort = (left, right, arr, ans) => {
// console.log(left)
// console.log("*****")
// console.log(right)
// console.log("*****£££")
let i = 0,
j = 0,
k = 0;
let leftLen = left.length,
rightLen = right.length;
while (i < leftLen && j < rightLen) {
if (left[i] <= right[j]) {
arr[k] = left[i];
i++;
} else {
arr[k] = right[j];
ans += leftLen - i;
j++;
}
k++;
}
while (i < leftLen) {
arr[k] = left[i];
i++;
k++;
}
while (j < rightLen) {
arr[k] = right[j];
j++;
k++;
}
return { arr, ans };
};
let divideArray = (arr, ans) => {
if (arr.length < 2) return { arr, ans };
let N = arr.length;
let mid = Math.round(N / 2);
let left = arr.slice(0, mid);
let right = arr.slice(mid, N);
ans = ans;
let lans=divideArray(left, ans).ans;
let bAns=divideArray(right, ans).ans;
// console.log(bAns)
let blabla= mergeSort(left, right, arr, lans+bAns);
return blabla
};
let merge = (arr, ans) => {
let res=0+ divideArray(arr, ans).ans;
// console.log("asdad")
// console.log(res)
return res;
};
function main(input) {
let arr = [1,4,3,2,5];
let ans = 0;
let output = merge(arr, ans);
console.log('Final', output);
}
main();
I have persisted the count val inside your divide array and used it to merge the 2 counts from the split array i.e left and right direction split
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