I am new to coding for parallel processing and am attempting to implement a multithreaded Merge Sort algorithm. I am unclear on the proper usage of threads and how exactly it works, but I attempted to implement it anyway and this is where I landed. (tells me that slice is not a function)
function pMergeSort(input, done) {
const spawn = require('threads').spawn;
if (input.length< 2)
return input;
function partition(arr) {
let middle = Math.floor(arr.length / 2);
let left = arr.sclice(0, middle);
let right = arr.slice(middle + 1, arr.length);
}
let left,right=partition(input);
let task = spawn(pMergeSort).send(left).on('done', function (arr) {
if (result === undefined) {
for (let i = 0; i< n.length; i++) {
result[i] = n[i];
}
}else {
merge(result, n);
left.kill();
}
});
pMergeSort(right, function (n) {
if (result === undefined) {
for (let i = 0; i< n.length; i++) {
result[i] = n[i];
}
}else {
merge(result, n);
right.kill();
}
});
}
/*
function mergeSort (arr) {
if (arr.length === 1) {
// return once we hit an array with a single item
return arr
}
const middle = Math.floor(arr.length / 2) // get the middle item of the array rounded down
const left = arr.slice(0, middle) // items on the left side
const right = arr.slice(middle) // items on the right side
return merge(mergeSort(left), mergeSort(right))
}*/
// compare the arrays item by item and return the concatenated result
function merge(left, right) {
let result = []
let indexLeft = 0
let indexRight = 0
while (indexLeft < left.length && indexRight < right.length) {
if (left[indexLeft] < right[indexRight]) {
result.push(left[indexLeft])
indexLeft++
} else {
result.push(right[indexRight])
indexRight++
}
}
return result.concat(left.slice(indexLeft)).concat(right.slice(indexRight))
}
function genArray(size) {
// randomly fills arr
var arr = Array(size);
for (var i = 0; i < size; i++) {
arr[i] = Math.floor(Math.random() * 98);
}
return arr
}
function testParallel(){
var array=genArray(Math.floor(Math.random()*100));
pMergeSort(array, function(i){
console.log(JSON.stringify(i));
})
}
var testArr = genArray(2);
pMergeSort(testArr, function (i) {
console.log(JSON.stringify(i));
});
help implementing this would be amazing, but some simple questions that could push me in the right direction is, is the merge of pMergeSort supposed to be a callback function? how do you define your call back function? Would it be better to use a pool of threads rather than trying to spawn threads? And the function wrapped in pMergeSort should be merge sort + splitting into threads right?
Related
how to get all the subarrays in O(nlog(n)) time complexity using javaScript
I try with a nested loop but the time complexity is in O(n*n). I heard about some prefix solutions but have no information
try this code :
fetechArray = (array) => {
for ( let subarray of array ){
// ur code here
fetechArray(subarray);
}
}
Use the "divide & conquer" approach. You first divide the original array into two halves, then combine the results from both halves to get all subarrays.
function subArrays(arr) {
if (arr.length === 1) {
return [arr];
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
const leftSubArrays = subArrays(left);
const rightSubArrays = subArrays(right);
return merge(leftSubArrays, rightSubArrays);
}
function merge(left, right) {
const result = [];
for (let i = 0; i < left.length; i++) {
for (let j = 0; j < right.length; j++) {
result.push(left[i].concat(right[j]));
}
}
return result;
}
I need to test Combinational Sum I algorithm using JavaScript. I have done all things in html, but I don't know how to call function (in script.js), which contain Combinational Sum I algorithm, correctly. Does anybody know how to call it? how to calculate? how to write test?
let botun=document.getElementById('botun');
//including variables
botun.onclick=function(){
let niz=document.getElementById('input').value;
let target=document.getElementById('target').value;
//convert string in array
let nizInt=niz.split(' ').map(Number);
//convert element of array in Int
let nizIntNovi=[];
for(var i=0; i<nizInt.length; i++) {
nizInt[i] = parseInt(nizInt[i], 10);
nizIntNovi[i]=nizInt[i];
}
console.log(nizIntNovi);
//calling function
let meduRez=combinationalSum(nizIntNovi,target);
console.log(meduRez);
}
// Javascript program to find all combinations that
// sum to a given value
var combinationalSum=function(candidates,target){
//global result
const result=[];
candidates.sort((a,b)=>a-b);
//dfs recursive helper
const dfs=(i,candidates,target,slate)=>{
//backtracking case
if(target<0) return;
//base case
if(target===0){
result.push(slate.slice());
return;
}
//dfs recursive case
for(let j=i;j<candidates.lenght;j++){
slate.push(candidates[j]);
dfs(j,candidates,target-candidates[j],slate);
slate.pop();
}
}
dfs(0,candidates,target,[]);
return result;
};
You call it like in the snippet below, with some basic HTML.
Or using the console of the browser.
The function is not working right.
You can read about implementation here https://www.geeksforgeeks.org/combinational-sum/
let botun = document.getElementById('botun');
//including variables
botun.onclick = function() {
let niz = document.getElementById('input').value;
let target = document.getElementById('target').value;
//convert string in array
let nizInt = niz.split(' ').map(Number);
//convert element of array in Int
let nizIntNovi = [];
for (var i = 0; i < nizInt.length; i++) {
nizInt[i] = parseInt(nizInt[i], 10);
nizIntNovi[i] = nizInt[i];
}
console.log(nizIntNovi);
//calling function
let meduRez = combinationalSum(nizIntNovi, target);
console.log(meduRez);
}
// Javascript program to find all combinations that
// sum to a given value
var combinationalSum = function(candidates, target) {
//global result
const result = [];
candidates.sort((a, b) => a - b);
//dfs recursive helper
const dfs = (i, candidates, target, slate) => {
//backtracking case
if (target < 0) return;
//base case
if (target === 0) {
result.push(slate.slice());
return;
}
//dfs recursive case
for (let j = i; j < candidates.lenght; j++) {
slate.push(candidates[j]);
dfs(j, candidates, target - candidates[j], slate);
slate.pop();
}
}
dfs(0, candidates, target, []);
return result;
};
input {
height: 30px;
width: 100px;
line-height: 1;
}
.as-console-wrapper {
max-height: 100% !important;
}
Input: <input id="input" value="1 2 3 4"> Target: <input id="target" value="6">
<input type="button" id="botun" value="click">
There is solved problem. Task: input array of integer, input target then calculate Combinational Sum and print the smallest array of Combinational Sum.
For example: Input: [2,4,6] Target:4. Output will be 1, because Combinational Sum prints (2+2),(4). Smaller array is 4 and it contains one element so 1 will be output!
Code:
let botun=document.getElementById('botun');
let nizSplitNew=[];
let targetNew;
let brojac;
let array=[];
let min;
var rezultat=document.getElementById("rezl");
//including variables
botun.onclick=function(){
let niz=document.getElementById('input').value;
let target=document.getElementById('target').value;
//convert string in array
let nizSplit=niz.split(',').map(Number);
//convert element of array in Int
for(var i=0; i<nizSplit.length; i++) {
nizSplitNew[i] = parseInt(nizSplit[i], 10);
}
console.log(nizSplitNew);
targetNew = parseInt(target, 10);
//calling function
let meduRez=combinationSum(nizSplitNew,targetNew);
// Javascript program to find all combinations that
// sum to a given value
function combinationSum(arr, sum) {
let ans = new Array();
let temp = new Array();
// first do hashing since hashset does not always
// sort
// removing the duplicates using HashSet and
// Sorting the arrayList
let set = new Set([...arr]);
arr = [...set];
arr.sort()
findNumbers(ans, arr, sum, 0, temp);
return ans;
}
function findNumbers(ans, arr, sum, index, temp) {
if (sum == 0) {
// pushing deep copy of list to ans
ans.push([...temp]);
return;
}
for (let i = index; i < arr.length; i++) {
// checking that sum does not become negative
if ((sum - arr[i]) >= 0) {
// pushing element which can contribute to
// sum
temp.push(arr[i]);
findNumbers(ans, arr, sum - arr[i], i, temp);
// removing element from list (backtracking)
temp.splice(temp.indexOf(arr[i]), 1);
}
}
}
// Driver Code
// arr.push(5);
// arr.push(4);
// arr.push(8);
//let arr = []
for(let i=0;i<nizSplitNew;i++){
nizSplitNew.push(nizSplitNew[i]);
}
let sum = targetNew;
let ans = combinationSum(nizSplitNew, sum);
// If result is empty, then
// print all combinations stored in ans
for (let i = 0; i < ans.length; i++) {
brojac=0;
for (let j = 0; j < ans[i].length; j++) {
brojac=brojac+1;
}
array.push(brojac);
}
console.log(array);
min = Math.min(...array);
if (array.length == 0) {
rezultat.innerHTML=`<p>-1</p>`
}
else{
rezultat.innerHTML=`<p>${min}</p>`
}
}
I'm trying the following logic and not sure which array function can help. I'm not able to use map or es6 but would like to see an answer.
I tried the following:
/* JS */ - This is not working and would like to see how to make it work.
var input = ['x','y','z'];
var powerSetResult = powerSet(input);
console.log(powerSetResult);
/*Ouput should be [''.'x','y','z','xy,'xz','yz','xyz']*/
function powerSet(arr) {
var data = [];
for(var i=0; i<arr.length; i++) {
arr[i] = arr[i] + arr[i+1];
data.push(arr[i]);
}
console.log(data);
return data;
}
/* ES 6 */ - Is there a better way to do this?
let input = ['x','y','z'];
let powerSetResult = powerSet(input);
console.log(powerSetResult);
/*Ouput should be [''.'x','y','z','xy,'xz','yz','xyz']*/
const powerSet(arr) {
let data = arr.map(([s1, s2, s3]) => [``,`${s1}`,`${s2}`,`${s3}`,`${s1}${s2}`,`${s1}${s3}`,`${s2}${s3}`,`${s1}${s2}${s3}`]);
console.log(data);
return data;
}
Certainly not the most efficient... but you could do this:
var input = ['x','y','z'];
var powerSetResult = powerSet(input);
console.log(powerSetResult);
function powerSet(arr, result) {
result = result || new Set();
const str = arr.join('');
for (let i = 0; i < arr.length; i++) {
for (let j = i; j <= arr.length; j++) {
result.add(str.slice(i, j));
}
powerSet([...arr.slice(0, i), ...arr.slice(i+1)], result)
}
return Array.from(result).sort((a, b) => {
return (a.length - b.length) || a.localeCompare(b);
});
}
/* Output should be [''.'x','y','z','xy,'xz','yz','xyz'] */
Caveat being it will only work for single letter elements, but is easily modifiable to accommodate more.
My merge sort visualizer draws the array but does not show them being sorted and doesnt seem to be correctly merging them and displaying each step. instead of returning a sorted array, I see a quick flash of the array then a blank screen.
values is the array and states is supposed to change in value from -1 to 1 based on whether an index is currently in progress, waiting, or completed but I'm trying to get the sort and merge working first.
//array of values to be sorted
let values = [];
//width of values
let w = 2;
//hold the state of the array
let states = [];
function setup() {
createCanvas(windowWidth, windowHeight);
values = new Array(floor(random(250, width / w)));
for (i = 0; i < values.length; i++) {
values[i] = random(height);
states[i] = -1;
}
}
async function mergeSort(arr) {
if (arr.length <= 1) {
return arr;
}
//get midpoint
let mid = Math.round(arr.length / 2);
states[mid] = -1;
//split the array
temp1 = arr.slice(0, mid);
temp2 = arr.slice(mid, arr.length);
//merge the array
await Promise.all([
merge(mergeSort(temp1), mergeSort(temp2))
]);
}
async function merge(arr1, arr2) {
await sleep(25);
let sorted = [];
while (arr1.length > 0 && arr2.length > 0) {
(arr1[0] < arr2[0]) ? sorted.push(arr1.shift()):
sorted.push(arr2.shift());
}
while (arr1.length > 0) {
sorted.push(arr1.shift());
}
while (arr2.length > 0) {
sorted.push(arr2.shift());
}
values = sorted.slice();
}
function draw() {
background(0);
mergeSort(values);
for (let i = 0; i < values.length; i++) {
noStroke();
if (states[i] == 0) {
fill('#38e332');
} else if (states[i] == 1) {
fill('#c9c8c7');
} else {
fill(255);
}
//draw the array values at location x=i*w , y=height-array[i] with given width (w) and height(array[i])
rect(i * w, height - values[i], w, values[i]);
}
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
'
I encountered this question:
Find longest decrease sequence in an array
So basically, if [3,1,4,3,2,1,2,3] is given, it will return [4,3,2,1] as the longest sequence within it. I was able to solve this question with O(n^2) time complexity but I feel like I can do O(n).
I know I am probably making a giant logic mistake but this is how I approach with 2 pointers method.
function findDecreaseSubArray(arr) {
let subList = [arr[0]];
// let maxLength= 0;
let left = 0;
for (let right = 1; right < arr.length; right++) {
// maxLength = (maxLength, windowEnd - windowStart + 1);
if (arr[left] > arr[right]) {
subList.push(arr[right]);
}else{
subList.shift();
left = right-1;
}
}
}
What I am trying to accomplish is moving left and right pointers if left element is larger than right, and if so, push both elements into sublist array.
My brain starts giving 404 error after this, so there are 2 subarrays that are decreasing, one of them is [3,1] and the other one is [4,3,2,1].
How could I track one subarray is larger than the other subarray? Or there is a better way to approach this solution?
Any hints, hands, code snippet would highly appreciated. (And sorry about my code snippet, I know it is shitty but I just wanted to display some of my thoughts on code)
You just have to iterate over the array once, but keep track of the start and length of the longest sequence as you progress through it:
var arr = [3,1,4,3,2,1,2,3];
function findDecreaseSubArray(arr) {
let startIndex = 0;
let length = 1;
let longestSequence = {
startIndex: 0,
length: 1
}
arr.forEach((element, index, arr) => {
if (index === 0) return;
if (element < arr[index -1]) {
length += 1;
} else {
length = 1;
startIndex = index;
}
if (length > longestSequence.length) {
longestSequence.length = length;
longestSequence.startIndex = startIndex;
}
})
return longestSequence;
}
console.log(findDecreaseSubArray(arr));
This approach supports VLAZ's comment and uses only the indices of the array.
function longestDecreasing(array) {
var longest,
start = 0,
i;
for (i = 0; i < array.length; i++) {
if (!i || array[i] < array[i - 1]) continue;
if (!longest || longest[1] - longest[0] < i - start) longest = [start, i];
start = i;
}
return array.slice(...longest && longest[1] - longest[0] > i - start
? longest
: [start, i]);
}
console.log(longestDecreasing([3, 1, 4, 3, 2, 1, 2, 3]))
It would probably be easier to iterate normally, from the first index to the end, while pushing sequential sequences to an array, which gets reset when a number greater than the last is found. When resetting, assign the resulting sequence array to a more permanent variable if it's longer than the array in that permanent variable:
const findDecreaseSubArray = (arr) => {
let longestSoFar = [];
let currentSequence = [];
const reset = (newItem) => {
if (currentSequence.length > longestSoFar.length) {
longestSoFar = currentSequence;
}
currentSequence = [newItem];
};
for (const item of arr) {
if (currentSequence.length && item > currentSequence[currentSequence.length - 1]) {
reset(item);
} else {
currentSequence.push(item);
}
}
reset();
return longestSoFar;
};
console.log(findDecreaseSubArray([3,1,4,3,2,1,2,3]));
Here is my code.
function getLongestDecreaseSequence(arr) {
if (
Object.prototype.toString.call(arr) !== "[object Array]" ||
arr.length == 0
) {
return arr;
}
let longestArr = [];
let tmpArr = [],
lastTmpIndex = -1;
arr.forEach((value, i) => {
if (arr[lastTmpIndex] < value) {
tmpArr = [];
}
// no matter what, I will put it in tmpArray
lastTmpIndex = i;
tmpArr.push(value);
if (longestArr.length < tmpArr.length) {
longestArr = tmpArr;
}
});
return longestArr;
}
console.log(getLongestDecreaseSequence([3, 1, 4, 3, 2, 1, 2, 3]));
This looks like a reducing job.
var a = [3,1,4,3,2,1,2,3],
r = a.reduce( function(r,e){
var l = r[r.length-1];
return l[l.length-1] > e ? ( l.push(e)
, r
)
: ( r.push([e])
, r
);
}
, [[]]
)
.reduce((p,c) => p.length > c.length ? p : c);
console.log(r);