Can there be an efficient way for the dual loops? - javascript

I got a question in exam where I was given an array a
a = [9,8,10,2]
what I need to do is cross iterate the array on itself and get the concatenation of all the possible elements i.e a*a
Once all elements are concatenated in that order, then I need to sum them up. My code is in the snippet:
Also tried in PHP
function sumIt($a) {
$totalSum = 0;
$len1 = count($a);
for($i = 0; $i < $len1; $i++){
for($ii = 0; $ii < $len1; $ii++) {
$totalSum += $a[$i].''.$a[$ii];
}
}
return $totalSum;
}
The input array a can have the following value constraints:
The length of array can be at max 10^5
Value of individual item can be unto 10^6
My code works fine mostly, but on higher end values for array a I start getting time exceed errors which is MAX 4 seconds. I tried with while & foreach loops with no effect. As the code is quite simple, I was wondering if anyone can provide hints on increasing the performance and reducing the execution time.
PS: I tried the --i thing in for loop as well if anyone knows, no difference in that regard as well.
a = [10, 23, 4857, 3, 49, 293, 1, 394,85, 392, 484, 392, 30, 4849,48, 20, 3948, 2493, 84, 3492, 384,92, 384,38, 49, 45, 489, 53,40,9875, 84,9,572,3958, 346,456,45, 56,4564, 6,7867,8, 78,9789, 234,234, 435,34,6, 45,345, 4564,5, 657,45, 45, 345, 667, 5,6756, 877,68, 6765,4, 34, 6, 54, 3, 654, 6, 5, 8776, 43, 32, 67, 89, 876,543,2,34,5, 654, 35, 6, 4, 345, 678, 9, 8, 765, 467,878,9, 4352, 5, 6743, 4, 47, 57,65, 345, 78, 765, 645,63, 56, 5786, 676, 4564,5, 42, 46, 786, 97, 896,567,86, 3777, 65, 6, 877, 65, 67, 2039757584,5348];
function sumIt(a) {
totalSum = 0;
const len1 = a.length;
for(let i = 0; i < len1; i++){
for(let ii = 0; ii < len1; ii++) {
totalSum += +(a[i]+''+a[ii]);
}
}
return totalSum;
}
currentTime = new Date().getTime();
console.log(sumIt(a));
console.log(new Date().getTime() - currentTime);
function sumIt2(a) {
totalSum = 0;
const len1 = a.length;
for(let i = 0; i < len1; i++){
first = Math.pow(10, Math.ceil(Math.log(a[i] + 1)));
for(let j = 0; j < len1; j++) {
totalSum += (first + a[j])
}
}
return totalSum;
}
currentTime = new Date().getTime();
console.log(sumIt2(a));
console.log(new Date().getTime() - currentTime);

The following algorithm (based on #user3386109's idea) is way quicker:
// Generate random array
let a = [];
for (let i = 0; i < 100; i++) {
a.push(Math.floor(Math.random() * 1e6));
}
function sumIt(a) {
totalSum = 0;
const len1 = a.length;
for(let i = 0; i < len1; i++){
for(let ii = 0; ii < len1; ii++) {
totalSum += +(a[i]+''+a[ii]);
}
}
return totalSum;
}
function sumIt2(a) {
let total = 0;
let aLen = a.length;
for (let i = 0; i < aLen; i++) {
for (let j = 0; j < aLen; j++) {
var subtotal = a[i] * Math.pow(10, Math.ceil(Math.log10(a[j] + 1))) + a[j];
total += subtotal;
}
}
return total;
}
function sumIt3(a) {
let subtotal = 0;
let multiplier = 0;
let digitCounts = [a.length, 0, 0, 0, 0, 0, 0];
for (let i = 0; i < a.length; i++) {
subtotal += a[i];
digitCounts[Math.ceil(Math.log10(a[i] + 1))]++;
}
for (let i = 0; i < digitCounts.length; i++) {
multiplier += Math.pow(10, i) * digitCounts[i];
}
return subtotal * multiplier;
}
console.clear();
performance.mark("start");
console.log(sumIt(a));
performance.mark("sumIt");
console.log(sumIt2(a));
performance.mark("sumIt2");
console.log(sumIt3(a));
performance.mark("sumIt3");
performance.measure("sumIt", "start", "sumIt");
performance.measure("sumIt2", "sumIt", "sumIt2");
performance.measure("sumIt3", "sumIt2", "sumIt3");
console.log(performance.getEntriesByType("measure").map(p => p.duration));
However, with larger array sizes (above about 140), the results start to diverge. I think that is more to do with the precision of JS's Number type rather than an underlying problem in the algorithm.

Related

Find max sum submatrix in 2D array/matrix

Please find my current implementation below:
function findMaxSumSubMatrix(matrix) {
var dim = matrix[0].length;
// initialize prefix sum matrix
var ps = new Array();
for (var _ = 0; _ < dim; _++) {
ps[_] = new Array();
}
// calculate vertical prefix sum matrix
for (var i = 0; i < dim; i++) {
for (var j = 0; j < dim; j++) {
if (j == 0) {
ps[j][i] = matrix[j][i];
} else {
ps[j][i] = matrix[j][i] + ps[j - 1][i];
}
}
}
// console.log(ps); // log prefix sum matrix
var maxSum = 0;
var min, temp;
// using the prefix sum matrix, iterate over all combinations and keep track of the max (Kadane's algorithm)
for (var i = 0; i < dim; i++) {
for (var j = i; j < dim; j++) {
min = 0;
temp = 0;
for (var k = 0; k < dim; k++) {
if (i == 0) {
temp += ps[j][k];
} else {
temp += ps[j][k] - ps[i - 1][k];
}
if (temp < min) {
min = temp;
}
if (temp - min > maxSum) {
maxSum = temp - min;
}
}
}
}
return maxSum;
}
var example1 = [
[1, -61, 5126, 612, 6],
[41, 6, 7, 2, -7],
[1, 73, -62, 678, 1],
[7, -616136, 61, -83, 724],
[-151, 6247, 872, 2517, 8135],
];
console.log(findMaxSumSubMatrix(example1)); // expected output: 18589
This works as expected, the output is correct.
However, I didn't write the code myself entirely.
What is unclear to me is the "min" and this part:
if (temp < min) {
min = temp;
}
if (temp - min > maxSum) {
maxSum = temp - min;
}
Can someone explain to me what's happening there, and why it's needed? I tried omitting it, giving incorrect results.
Thank you.
Think of this as a simple 1D array, where you have to find the maximum contiguous subsequence sum (exactly what Kadane's Algorithm does). For each prefix sum, you'll consider the lowest prefix sum that precedes it and calculate the difference (picking the lowest because you need to maximise the difference).
Similarly, the 2D array here also stores the prefix sum. We use min to keep a track of the lowest sum encountered in the current column. Since we need the maximum sum, we try to maximise the difference between current prefix sum (that is temp) and the minimum sum encountered (that is min).

Array Sorting not working in JS

I have array like this
value = [250, 200, 300, 150, 300]
I use this code.
for (var j = 0; j < value.length - 1; j += 1)
{
if (value[j] > value[j + 1])
{
var temp = value[j + 1];
value[j + 1] = value[j];
value[j] = temp;
}
}
But,it's not working. It's results value = [200, 250, 150, 300, 300]
I want to acheive this without using inbuilt function.
use the below code.
var value = [250, 200, 300, 150, 300];
for (var i = 0; i < value.length; i++) {
var swapped = false
for (var j = 0; j < value.length; j++) {
if (value[j] > value[j + 1]) {
temp = value[j + 1];
value[j + 1] = value[j];
value[j] = temp;
swapped = true;
}
}
if (!swapped) {
break;
}
}
console.log(value)
var numbers = [10, 3, 5, 1, 88, 6, 12, 28, 16]
for (var i = 0; i < numbers.length; i++) {
for (var j = 0; j < numbers.length; j++) {
if (numbers[i] < numbers[j]) {
var temp = numbers[j];
numbers[j] = numbers[i];
numbers[i] = temp;
}
}
}
console.log(numbers);
You should have two loops one inside other to sort array
value = [250, 200, 300, 150, 300]
for (var i = 0; i < value.length; i++)
for (var j = i; j < value.length - 1; j++) {
if (value[i] > value[j]) {
var temp = value[j];
value[j] = value[i];
value[i] = temp;
}
}
console.log(value)

How to sort a 2D array in Javascript using bubble sort

This is my function and need help making it work with a 2D array so when I pass
[ [39, 43, 32], [300, 44, 1] ]
It returns
[ [1, 32, 39], [43, 44, 300] ]
function bubbleSort(items) {
var length = items.length;
for (var i = 0; i < length; i++) {
for (var j = 0; j < (length - i - 1); j++) {
if(items[j] > items[j+1]) {
var tmp = items[j];
items[j] = items[j+1];
items[j+1] = tmp;
}
}
}
}
For the exact example you've given the solution could be to just concatenate the two sub-arrays, sort the result and part the result into two sub-arrays.
function bubbleSort(items) {
var length = items.length;
for (var i = 0; i < length; i++) {
for (var j = 0; j < (length - i - 1); j++) {
if(items[j] > items[j+1]) {
var tmp = items[j];
items[j] = items[j+1];
items[j+1] = tmp;
}
}
}
return items;
}
var a = [ [39, 43, 32], [300, 44, 1] ];
var a2 = bubbleSort(a[0].concat(a[1]));
a[0] = a2.slice(0,3);
a[1] = a2.slice(3,6);
This will get quite slow, if the array has many entries. It will also fail if the entries have different lengths. If they have different lengths you need the parse the array first and save the individual lengths in a second array to part the result correctly at the end. Concatenating and sorting would be the same.
Probably the best solution is to first "unnest" the nested array into a flat array, sort it, and copy the values back into the nested array:
function bubbleSortNested(items) {
// create a flat copy of the nested items array
var flat = [];
for (var i = 0; i < items.length; i++) {
flat = flat.concat(items[i]);
}
// sort flat array
for (var i = 0; i < flat.length; i++) {
for (var j = 0; j < (flat.length - i - 1); j++) {
if(flat[j] > flat[j+1]) {
var tmp = flat[j];
flat[j] = flat[j+1];
flat[j+1] = tmp;
}
}
}
// copy sorted flat array back into original nested array
for (var i = items.length-1; i>=0; i--) {
items[i] = flat.slice(-items[i].length);
flat.length -= items[i].length;
}
return items;
}
res = bubbleSortNested([ [39, 43, 32], [300, 44, 1] ]);
console.log(res);
Output:
[ [1, 32, 39], [43, 44, 300] ]

How to write shell sort on Node.js

I'm trying to write a shellsort on Node.js like on the book Algorithms, 4th ed. Sedgewick, Wayne. There all the examples written on Java.
Here is my module:
"use strict";
module.exports = (function() {
function sort(array) {
let size = array.length;
let h = 1;
while(h < size/3) {
h = h * 3 + 1;
}
while(h >= 1) {
for(let i = h; i < size; i++) {
for(let j = i; j >= h && less(array, j, j-h); j = j-h) {
exch(array, j, j-h);
}
}
h = h/3;
}
}
function less(array, i, min) {
return array[i] < array[min];
}
function exch(array, i, min) {
let temp = array[i];
array[i] = array[min];
array[min] = temp;
}
return {
sort: sort
};
})();
I use mocha and chai for testing with this function:
function isSorted(array) {
for(let i = 1, size = array.length; i < size; i++) {
if (array[i] < array[i-1]) {
return false;
}
}
return true;
}
and shell sort not working: mocha test screenshot
Your h may become a floating point number if you use h = h / 3. Try h = Math.floor(h / 3); instead.
Implementation of shell sort algorithm in Javascript
function shellSort(arr){
var len = arr.length;
var gapSize = Math.floor(len/2);
while(gapSize > 0){
for(var i = gapSize; i < len; i++) {
var temp = arr[i];
var j = i;
while(j >= gapSize && arr[j - gapSize] > temp) {
arr[j] = arr[j - gapSize];
j -= gapSize;
}
arr[j] = temp;
}
gapSize = Math.floor(gapSize/2);
}
return arr;
}
function isSorted(array) {
for(let i = 1, size = array.length; i < size; i++) {
if (array[i] < array[i-1]) {
return false;
}
}
return true;
}
var randomArray = [45,86,3,5,97,95,4,24,7,88,93,27,45,90,54,89,74,5,90,73,74,857,834,8394,4231,485,32,54,674,12];
var mySortedArray = shellSort(randomArray);
console.log(mySortedArray);
console.log(isSorted(mySortedArray));
Output:
[3, 4, 5, 5, 7, 12, 24, 27, 32, 45, 45, 54, 54, 73, 74, 74, 86, 88, 89, 90, 90, 93, 95, 97, 485, 674, 834, 857, 4231, 8394]
true

Simple javascript program

I'm just getting started on learning javascript, and I'm creating this simple program that takes the largest numbers from an array, and put them in a new array, which will be returned in the end.
The function is called largestOf(), and for example,
largestOf([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]]) should return [27,5,39,1001].
What I have so far is this, and I don't know how to fix it, or if it has something to do with the way I am utilizing the brackets.
function largestOf(arr) {
var nArr = [];
for (var i = 0; i < arr.length; i++) {
n = arr[i].length;
max = 0;
for(var j = 0; j < n; j ++) {
if (arr[i][j] > max) {
max = arr[i][j];
nArr.push(max);
}
}
}
return nArr;
}
What I am trying to do here is pretty straightforward. I'm running through every block in the array, picking the max, and putting that max in its own array (nArr) with the other max's.
I want to know how to fix what I have while still doing it my way.
Thank you
function largestOf(arr) {
var nArr = [];
for (var i = 0; i < arr.length; i++) {
var n = arr[i].length;
var max = 0;
for (var j = 0; j < n; j++) {
if (arr[i][j] > max) {
max = arr[i][j];
}
}
nArr.push(max); // push your max outside of the inner loop
}
return nArr;
}

Categories

Resources