Why these two loops return different results? - javascript

Problem statement
Given an array arr, find element pairs whose sum equal the second
argument arg and return the sum of their indices.
Disclaimer, I am not asking for the solution of this problem statement, but about the confusion between the following two loops I tried creating, whose functionality is almost exactly similar but consoling different outputs.
First Loop
function pairwise(arr, arg) {
const indexOfPair = []
for ( let i = 0; i < arr.length -1; i++){
for (let j = i + 1; j < arr.length -1; j++ ){
let sum = arr[i] + arr[j]
if ( sum === arg){
indexOfPair.push(arr.indexOf(arr[i]), arr.indexOf(arr[j]))
}
else {
continue
}
}
}
console.log(indexOfPair)
console.log(indexOfPair.reduce((a, b) => a + b, 0))
}
pairwise([1,4,2,3,0,5], 7);
Console Output:[1,3] & 4
Second Loop
function pairwise(arr, arg) {
const indexOfPair = []
for ( let i = arr.length - 1; i >= 0 ; i--){
for (let j = i -1; j >= 0; j--){
let sum = arr[i] + arr[j]
if ( sum === arg){
indexOfPair.push(arr.indexOf(arr[i]), arr.indexOf(arr[j]))
}
}
}
console.log(indexOfPair)
console.log(indexOfPair.reduce((a, b) => a + b, 0))
}
pairwise([1,4,2,3,0,5], 7);
Console output: [5,2,3,1] & 11 -> This is the expected output and I am not getting why these two loops are returning different outcomes.

You're not getting to the last entry in arr.
for ( let i = 0; i < arr.length - 1; i++){
for (let j = i + 1; j < arr.length - 1; j++ )
should be
for ( let i = 0; i <= arr.length - 1; i++){
for (let j = i + 1; j <= arr.length - 1; j++ )

Related

Fill matrix with snake pattern using javascript

I want to fill in a 2D array of numbers with snake pattern, I tried this algorithm but the result it's not the expected:
function fill2d(c,l) {
var arr = new Array[l][c];
let counter = 0;
for (let col = 0; col < arr.l; col++) {
if (col % 2 == 0) {
for (let row = 0; row < arr.l; row++) {
arr[row][col] = counter++;
}
} else {
for (let row = arr.length - 1; row >= 0; row--) {
arr[row][col] = counter++;
}
}
}
return arr;
}
fill2d(4,4)
some thing like that :
1 2 3 4
8 7 6 5
9 10 11 12
16 15 14 13
Okay so basically all you need is to traverse row-by-row but alternating between left-to-right and right-to-left. Here's my solution:
function fill2d(c, l) {
let arr = new Array(l);
for (var i = 0; i < l; i++) {
arr[i] = new Array(c);
}
let count = 1;
for (let i = 0; i < l; i++) {
console.log("i: ", i);
let right_to_left = i % 2;
for (let j = (right_to_left * (l - 1));
(right_to_left ? (j >= 0) : (j < c)); j += (right_to_left ? -1 : 1)) {
console.log("j: ", j);
arr[i][j] = count++;
}
}
return arr;
}
console.log(fill2d(4, 4));
Also, you weren't allocating a 2d array properly, you need to allocate a 1d array first and then allocate an array for each of the elements of that array.
Note: I added logs for each i and j so that you can see how the array is traversed.

How to make a loop that go up and down at the same time?

i was wandering how to make a loop that go up and down at the same time.
For example, here is the normal loop:
for(let i = 0; i < number.length; i++){}
for(let i = 0; i < number.length; i--){}
How can i simplify this loop?
You can have as many indexes as you want in a for loop:
a = [1,2,3,4,5,6,7]
for (let i = 0, k = a.length - 1; i < a.length && k >= 0; i++, k--) {
console.log(i, k)
}
or, you can compute the second index from the first
a = [1,2,3,4,5,6,7]
for (let i = 0; i < a.length; i++) {
let k = a.length - 1 - i
console.log(i, k)
}
If you want to do that in the modern way, without any indexes at all, this would require some runtime support:
function* iter(a) {
yield* a;
}
function* reversed(a) {
yield* [...a].reverse();
}
function* zip(...args) {
let iters = args.map(iter);
while (1) {
let rs = iters.map(it => it.next());
if (rs.some(r => r.done))
break;
yield rs.map(r => r.value);
}
}
//
a = 'abcdef'
// just like in python!
for (let [x, y] of zip(a, reversed(a)))
console.log(x, y)
You could just embed 2 loops. Such as:
for(let i = 0; i < number.length; i++){ // i going "up"
for(let j = number.length; j > 0; j--){} // j going "down"
}
If you want to get the values from first to the last value and vise versa at the same time you don't have to use double loops. Instead just use the i and arrays length. Here's an example.
var length = number.length - 1
for(let i = 0; i < number.length; i++){
console.log(number[i])
console.log(number[length-i])
}

How to Sort an Array of Numbers of String Datatype without using Inbuilt sort() and atoi method in JavaScript

I am trying sort the below given Array without converting the strings to number(without atoi function) and also without using sort() inbuilt function
inputArr = ["1","2","10","3","21","15"]
let len = inputArr.length;
for (let i = 0; i < len; i++) {
for (let j = 0; j < len; j++) {
if (inputArr[j] > inputArr[j + 1]) {
let tmp = inputArr[j];
inputArr[j] = inputArr[j + 1];
inputArr[j + 1] = tmp;
}
}
}
return inputArr;
But the above code doesn't sort the numbers in correct order
Output Expected: ["1","2","3",,"10","15","21"]
You seem to be approaching the problem by using a BubbleSort, so tried to come up with a solution using the same algorithm.
The issue is with your comparison.
You will see that
"1" < "10" === true
But
"2" < "10" === false
So you need to check each character of the string to determine whether the number is actually smaller or not.
Here is the code:
const arr = ["1", "2", "10", "3", "21", "15"];
const len = arr.length;
const isGreater = (num1, num2) => {
if (num1.length < num2.length) return false;
for (let i = 0; i < len; ++i) {
if(num1[i] === num2[i]) continue;
return (num1[i] > num2[i]);
}
return false;
}
for (let i = 0; i < len; ++i) {
for (let j = 0; j < len - i - 1; ++j) {
if (arr[j].length > arr[j + 1].length || isGreater(arr[j], arr[j + 1])) {
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
console.log(arr);
The function isGreater will do that check for you.
inputArr = ["1","2","10","3","21","15"]
const sorted = inputArr.sort((a, b) => Number(a) - Number(b))
console.log(sorted);
const a = ["1","2","3",,"10","15","21"];
a.sort((x, y) => x-y);

Find largest d in array such that a + b + c = d

Task
You are given a sorted integer array arr. It contains several unique integers(negative, positive, or zero).
Your task is to find the largest d such that a + b + c = d, where a, b, c, and d are distinct elements of arr. If no such an element d found, return null.
Example:
For arr = [2,3,5,7,12], the output should be 12 (this array passes my function correctly)
For arr = [-100,-1,0,7,101], the output should be 0 (this one does not pass)
I could manage the positive numbers check but my function miserably fails with negatives
function findD(arr) {
myArr = arr.sort((a, b) => b - a);
for (var i = 0; i < myArr.length; i++) {
for (var k = i + 1; k < myArr.length - 2; k++) {
var j = k + 1,
d = myArr.length - 1;
while (j < d) {
let sum = myArr[k] + myArr[j] + myArr[d];
if (sum == myArr[i]) {
return myArr[i];
} else if (sum < myArr[i]) {
d--;
} else if (sum > myArr[i]) {
j++;
}
}
}
}
return null
}
how to handle negative values in the array?
Let's imagine there's an array like [-2, -1, 0, 3].
Then, after sorting it in the descending order as per your algorithm it will be [3, 0, -1, -2]. Obviously, your algorithm will pick only 3 as you assume d must be larger than numbers at the remaining 3 positions. That's wrong, of course. You shouldn't assume that a, b and c are necessarily less than d. That's why you must check other cases when d occupies all possible positions in relation to a,b,c. So, first consider a brute force approach that will have O(n^4) time and O(1) space complexity:
...
for (var i = myArr.length; i >= 0 ; i--) {
for (var k = 0; k < myArr.length; k++) {
if (k == i) {
continue
}
for (var j = k + 1; j < myArr.length; j++) {
if (j == i) {
continue
}
for (var d = j + 1; d < myArr.length; d++) {
if (d == i) {
continue
}
if (myArr[i] == myArr[k] + myArr[j] + myArr[d]) {
return myArr[i]
}
}
}
}
}
return null
...
But this problem can be solved in O(n^2) time and O(n^2) space.
First we should realise that a + b = d - c.
So, for the given array arr and every pair of indices i,j: i<j we store arr[i] + arr[j] (a + b) as a key and pair i,j as an item of a value (the value is a list of pairs of indices) in sumsMap. The value must be a list because there can be several pairs of indices corresponding to the same sum a + b.
Then, go through each pair of indices again k,l and check if a key arr[l] - arr[k] (d - c) or arr[k] - arr[l] (c - d) exists in sumsMap. If it does and indices l,k are different from the ones in sumsMap[s] then update the maximum element if it's lower than arr[l].
function solve(arr) {
var sumsMap = {}
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
var sum = arr[i] + arr[j]
// several pairs of indices can correspond to the same summ so keep all of them
var mappedIndices = sumsMap[sum]
if (typeof mappedIndices == "undefined") {
mappedIndices = []
}
let pair = {}
pair.first = i
pair.second = j
mappedIndices.push(pair)
sumsMap[sum] = mappedIndices
}
}
var maxD = Number.MIN_SAFE_INTEGER
for (var k = 0; k < arr.length; k++) {
for (var l = 0; l < arr.length; l++) {
mappedIndices = sumsMap[arr[l] - arr[k]]
if (mappedIndices != undefined) {
// in the worst case, 4 pairs of indices may contain k or l but the fifth one won't as numbers in the array are unique and hence the same index can occur only twice
var steps = Math.min(5, mappedIndices.length)
for (var s = 0; s < steps; s++) {
var pair = mappedIndices[s]
if (pair.first != k && pair.first != l && pair.second != k && pair.second != l) {
maxD = Math.max(maxD, arr[l])
}
}
}
}
}
if (maxD == Number.MIN_VALUE) {
return -1
} else {
return maxD
}
}
document.write(solve([-100,-1,0,7,101] ))
document.write("<br>")
document.write(solve([-93,-30,-31,-32] ))
I translated the function Renaldo suggested from https://www.geeksforgeeks.org/find-largest-d-in-array-such-that-a-b-c-d/ to JavaScript for you.
function findLargestd(S, n){
var found = false;
// sort the array in
// ascending order
S.sort((a, b) => a - b);
// iterating from backwards to
// find the required largest d
for(var i = n - 1; i >= 0; i--){
for(var j = 0; j < n; j++){
// since all four a, b, c,
// d should be distinct
if(i == j){
continue;
}
for(var k = j + 1; k < n; k++){
if(i == k){
continue;
}
for(var l = k + 1; l < n; l++){
if(i == l){
continue;
}
// if the current combination
// of j, k, l in the set is
// equal to S[i] return this
// value as this would be the
// largest d since we are
// iterating in descending order
if(S[i] == S[j] + S[k] + S[l]){
found = true;
return S[i];
}
}
}
}
}
//if not found, return 0
if(found === false){
return 0;
}
}

least common multiple: What is wrong with my code?

function lcm(arr) {
arr = arr.sort(function(a, b) {
return a - b;
});
var j = 1;
var num = arr[0];
for (i = 1; i < arr.length; i++) {
while (num % arr[i] !== 0) {
j = j + 1;
num = j * arr[0];
}
arr[0] = num;
}
return num;
}
console.log(lcm([3, 5, 6, 10]));
I am trying to find the least common multiple for a range of numbers in an array. The code works fine for array with two items, however the output for arrays with more than two items seems to exceed the value expected.
Can anyone help me find the bug in my code ?
Thank you
Set j back to 1 each time through the loop through the array elements. Otherwise, when you process the next number, you start with a high multiplier.
// function that find the least common multiple
function lcm(arr) {
arr = arr.sort(function(a, b) {
return a - b;
});
var num = arr[0];
for (i = 1; i < arr.length; i++) {
var j = 1;
while (num % arr[i] !== 0) {
j = j + 1;
num = j * arr[0];
}
arr[0] = num;
}
return num;
}
console.log(lcm([3, 5, 6, 10]));

Categories

Resources