Trying To Optimise Nested Loops - javascript

I have written some code which calculates the difference between each pair of elements in an array and counts how often the differences occur in the array.
I am trying to move from complexity O(n^3) to O(n^2), can someone help ?
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let n;
let a = [];
rl.on('line', (line) => {
if (!n) {
n = parseInt(line);
} else {
a = line.split(' ').map(x => parseInt(x));
let count = 0;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
for (let k = 0; k < n; k++) {
if (Math.abs(a[i] - a[j]) === a[k] && i < j) {
count++;
}
}
}
}
console.log(count);
rl.close();
}
});
i am expecting
from the input:
5
3 1 4 2 1
an output of :
13
const n = 5;
const a = [3, 1, 4, 2, 1];
let count = 0;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
for (let k = 0; k < n; k++) {
if (Math.abs(a[i] - a[j]) === a[k] && i < j) {
count++;
}
}
}
}
console.log(count);

You can easily remove the inner loop. Count the numbers. Use two nested loops to calculate the difference for each pair and increment using the counts. You can replace the inner loop with count += counts[Math.abs(a[i] - a[j])].
const n = 5;
const a = [3, 1, 4, 2, 1];
let count = 0;
const counts = a.reduce((acc, el) => (acc[el] = (acc[el] ?? 0) + 1, acc), []);
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
count += counts[Math.abs(a[i] - a[j])] ?? 0;
}
}
console.log(count);
The whole code:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let n;
let a = [];
rl.on('line', (line) => {
if (!n) {
n = parseInt(line);
} else {
a = line.split(' ').map(x => parseInt(x));
let count = 0;
const counts = a.reduce((acc, el) => (acc[el] = (acc[el] ?? 0) + 1, acc), []);
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
count += counts[Math.abs(a[i] - a[j])] ?? 0;
}
}
console.log(count);
rl.close();
}
});

Related

Two Sum Leetcode

I wrote the code, but for some reason it displays the index 1, 2, 3, while 3 + 4 will in no way be equal to target (6).
var twoSum = function(nums, target) {
let sum = [];
var n = 2;
for(let i = 0; i < nums.length; i++) {
for(let a = 1; a < nums.length; a++) {
if(nums[i] + nums[a] == target) {
sum.push(i);
sum.push(a);
}
}
}
let unique = sum.filter((e, i) => sum.indexOf(e) === i )
return unique/* .slice(0, n); */
};
console.log(twoSum([1,3,4,2],6))
Input
[1,3,4,2]
6
Output
[1,2]
Expected
[2,3]
As per my comment, start the inner loop at a = i + 1 to avoid summing numbers with themselves as well as to avoid checking the same combination twice, e.g (1, 2) and (2, 1):
var twoSum = function(nums, target) {
let sum = [];
let n = 2;
for (let i = 0; i < nums.length; i++) {
for (let a = i + 1; a < nums.length; a++) {
if (nums[i] + nums[a] === target) {
sum.push(i);
sum.push(a);
}
}
}
let unique = sum.filter((e, i) => sum.indexOf(e) === i )
return unique/* .slice(0, n); */
};

Anagram of strings of arrays

This program is working for a single word but I want to pass an array of strings(more than one word).
let output = getAnagrams("CATCH"); //it is working for this
let output = getAnagrams(["catch", "Priest", "Monkey", "Bruise"]);
I want it to work for this.
function swap(chars, i, j) {
var tmp = chars[i];
chars[i] = chars[j];
chars[j] = tmp;
}
function getAnagrams(input) {
let newInput = input.toString().toLowerCase();
console.log(newInput);
var counter = [],
anagrams = [],
chars = newInput.split(''),
length = chars.length,
i;
for (i = 0; i < length; i++) {
counter[i] = 0;
}
anagrams.push(newInput);
i = 0;
while (i < length) {
if (counter[i] < i) {
swap(chars, i % 2 === 1 ? Counter[i] : 0, i);
counter[i]++;
i = 0;
anagrams.push(chars.join(''));
} else {
counter[i] = 0;
i++;
}
}
// return anagrams;
}
As you already have a method which takes 1 string, why not just call it for each string in your array and then flatten the returning the array using flatMap
function getAnagrams(input) {
let newInput = input.toString().toLowerCase();
var counter = [],
anagrams = [],
chars = newInput.split(''),
length = chars.length,
i;
for (i = 0; i < length; i++) {
counter[i] = 0;
}
anagrams.push(newInput);
i = 0;
while (i < length) {
if (counter[i] < i) {
swap(chars, i % 2 === 1 ? counter[i] : 0, i);
counter[i]++;
i = 0;
anagrams.push(chars.join(''));
} else {
counter[i] = 0;
i++;
}
}
return anagrams;
}
function swap(arr,i,j){
const tmp = arr[i];
arr[i] = arr[j]
arr[j] = tmp
}
const result = ["catch", "Priest", "Monkey", "Bruise"].flatMap(i => getAnagrams(i))
console.log(result)

CodeWars sorting numbers and letters

I am currently doing a codewars problem, and I think I almost got it however, I ran across a problem when sorting index values with the same letter. link to problem is here. https://www.codewars.com/kata/5782dd86202c0e43410001f6
function doMath(s) {
let strSplit = s.split(' ');
let clonedArr = strSplit.slice();
for (let i = 0; i < strSplit.length; i++) {
for (let j = 0; j < strSplit[i].length; j++) {
let current = strSplit[i][j];
if (isNaN(current)) {
let letter = current;
strSplit[i] = strSplit[i].replace(letter, '');
strSplit[i] = letter + strSplit[i];
}
}
}
let sortedArr = strSplit.sort();
console.log(sortedArr);
// ["b900", "y369", "z123", "z246", "z89"]
let noLetterArr = sortedArr.map(x => {
return x.slice(1);
});
let numberArr = noLetterArr.map(y => {
return +y;
})
let firstEl = numberArr[0];
for (let i = 1; i < numberArr.length; i++) {
if (numberArr.indexOf(numberArr[i]) % 4 == 1) {
firstEl += numberArr[i];
}
if (numberArr.indexOf(numberArr[i]) % 4 == 2) {
firstEl -= numberArr[i];
}
if (numberArr.indexOf(numberArr[i]) % 4 == 3) {
firstEl *= numberArr[i];
}
}
return firstEl;
}
console.log(doMath('24z6 1z23 y369 89z 900b'));
I would like to sort the sortedArr the ones with the same letter by how they first appeared in string. So since "z246" appeared first in the original string. I would like to have that before "1z23". I had a hard time creating a function for that.
var al = [];
function doMath(s) {
var ar = s.split(" ");
for (let i = 0; i < ar.length; i++) {
for (let char of ar[i]) {
let temp = char.match(/[a-z]/i);
if (temp) {
al[i] = char;
ar[i] = ar[i].replace(char, '');
ar[i] = char + ar[i];
}
}
}
al = al.sort();
//New Sort Logic to pass above test case and others too
var n = [];
for (let i = 0; i < al.length; i++) {
for (let j = 0; j < ar.length; j++) {
if (ar[j].startsWith(al[i]) && !n.includes(ar[j])) {
n.push(ar[j]);
}
}
}
var result = parseInt(n[0].substr(1)),
count = 1;
for (let i = 1; i < n.length; i++) {
if (count == 1) {
result = result + parseInt(n[i].substr(1));
count++;
} else if (count == 2) {
result = result - parseInt(n[i].substr(1));
count++;
} else if (count == 3) {
result = result * parseInt(n[i].substr(1));
count++;
} else if (count == 4) {
result = result / parseInt(n[i].substr(1));
count = 1;
}
}
return Math.round(result);
}

get all subarray which have sum 0 in javascript?

I am trying to get all subarray which have sum 0 in javascript ? I am able to do that in O(n^2) like this
function getSubArray(input){
let result =[]
sum= 0
let a = [];
for(var i =0;i<input.length;i++){
a=[];
sum =0 ;
for (let j = i; j < input.length; j++) {
a.push(input[j])
sum+=input[j];
if(sum ===0){
result.push(a);
}
}
}
return result
}
when I call above function console.log(getSubArray([1, 2, -3, 0, 4, -5, 2, -1])) it is printed in all subarray but in O(n^2).
I tried to optimism this in O(n) using map
function getSubArray1(input) {
let sum = 0,
map = {0:[-1]};
for (let i = 0; i < input.length; i++) {
sum += input[i];
if (!map[sum]) {
map[sum] = [i];
}else {
map[sum].push(i)
let val = map[sum];
for (let j = 0; j < val.length; j++) {
console.log(val[j])
}
}
}
}
above function not working not giving all subarray? is there any way to do this?
I take the reference from here
https://www.techiedelight.com/find-sub-array-with-0-sum/
That site has an article titled "Find subarrays with given sum in an array". It has C++, Java, and Python implementations.
I just ported the Java (and a bit of Python) code to JavaScript.
const main = () => {
const input = [4, 2, -3, -1, 0, 4], target = 0;
console.log(subarraySum(input, target));
console.log(subarraySumMap(input, target));
};
const subarraySum = (nums, k) => {
const results = [];
for (let start = 0; start < nums.length; start++) {
let sum = 0;
for (let end = start; end <= nums.length; end++) {
sum += nums[end];
if (sum === k) {
results.push(nums.slice(start, end + 1));
}
}
}
return results;
}
const subarraySumMap = (nums, k) => {
const insert = (hashMap, key, value) =>
hashMap.set(key, (hashMap.get(key) || []).concat(value));
const results = [], hashMap = new Map();
let sum = 0;
insert(hashMap, 0, -1);
for (let index = 0; index < nums.length; index++) {
sum += nums[index];
if (hashMap.has(sum - k)) {
let list = hashMap.get(sum - k);
list.forEach(value => {
results.push(nums.slice(value + 1, index + 1));
});
}
insert(hashMap, sum, index);
}
return results;
}
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
<!-- References: -->
<!-- https://leetcode.com/problems/subarray-sum-equals-k/solution/ -->
<!-- https://www.techiedelight.com/find-subarrays-given-sum-array/ -->
<!-- ∀ x ⊆ ∑ { 4, 2, -3, -1, 0, 4 } = 0 -->

Creating a function to combine a nested array without recursion

I have the following array as an example;
let arr = [['red','blue','pink],['dog','cat','bird'],['loud', 'quiet']]
I need to write a generalized function that prints all combinations of one word from the first vector, one word from the second vector, etc. I looked up some codes on here but they are all recursion or working only with the specific array. How can I write this code without recursion?
let allComb = function(arr) {
if (arr.length == 1) {
return arr[0];
} else {
let result = [];
let arrComb = allComb(arr.slice(1));
for (let i = 0; i < arrComb.length; i++) {
for (let j = 0; j < arr[0].length; j++) {
result.push(arr[0][j] + ' ' + arrComb[i]);
}
}
return result;
}
}
allComb(arr)
This version uses a single increment per cycle technique with no recursion.
let arr = [
['red', 'blue', 'pink'],
['dog', 'cat', 'bird'],
['loud', 'quiet']
];
function allComb(arr) {
var total = 1;
var current = [];
var result = [];
for (var j = 0; j < arr.length; j++) {
total *= arr[j].length;
current[j] = 0;
}
for (var i = 0; i < total; i++) {
var inc = 1;
result[i] = "";
for (var j = 0; j < arr.length; j++) {
result[i] += arr[j][current[j]] + ' ';
if ((current[j] += inc) == arr[j].length)
current[j] = 0;
else
inc = 0;
}
}
return (result);
}
console.log(allComb(arr));
You may do as follows;
var arr = [['red','blue','pink'],['dog','cat','bird'],['loud', 'quiet']],
res = arr.reduce((p,c) => p.reduce((r,x) => r.concat(c.map(y => x + " " + y)),[]));
console.log(res);

Categories

Resources