What is the best way to shift a multidimensional array in Javascript? - javascript

I'm trying to create a javascript function that shifts an array right x units any up y units. It must keep the array size the same, and it must call unloadChunk for elements that are getting shifted off the multidimensional array. Here is my current implementation:
function shift(x, y) {
if (x > 0) {
for (var i = 0; i < chunks.length; i++) {
for (var j = chunks[i].length - 1; j >= 0; j--) {
if(j + x > chunks[i].length - 1 && chunks[i][j]) {
unloadChunk(i, j);
}
if (j < x) {
chunks[i][j] = null;
}
else {
chunks[i][j] = chunks[i][j - x];
}
}
}
}
else if (x < 0) {
for (var i = 0; i < chunks.length; i++) {
for (var j = 0; j < chunks[i].length; j++) {
if(j + x < 0 && chunks[i][j]) {
unloadChunk(i, j);
}
if (j - x >= chunks[i].length) {
chunks[i][j] = null;
}
else {
chunks[i][j] = chunks[i][j - x];
}
}
}
}
if (y > 0) {
for (var i = 0; i < chunks.length; i++) {
if (i + y >= chunks.length) {
for (var j = 0; j < chunks.length; j++) {
if(i - y < 0 && chunks[i][j]) {
unloadChunk(i, j);
}
chunks[i][j] = null;
}
}
else {
for (var j = 0; j < chunks.length; j++) {
if(i - y < 0 && chunks[i][j]) {
unloadChunk(i, j);
}
chunks[i][j] = chunks[i + y][j];
}
}
}
}
else if (y < 0) {
for (var i = chunks.length - 1; i >= 0; i--) {
if (i + y < 0) {
for (var j = 0; j < chunks.length; j++) {
if(i - y > chunks.length - 1 && chunks[i][j]) {
unloadChunk(i, j);
}
chunks[i][j] = null;
}
}
else {
for (var j = 0; j < chunks.length; j++) {
if(i - y > chunks.length - 1 && chunks[i][j]) {
unloadChunk(i, j);
}
chunks[i][j] = chunks[i + y][j];
}
}
}
}
}
If you're having trouble understanding exactly what I want the shift function to do, take a look at this fiddle and look at the html output.
My attempt at creating the shift function works, but it has 10 for loops. My question was, is there a more efficient, less verbose way to do this?

This proposal uses
Array#forEach: visit each item
Array#map: return value for each item
Array#pop: removes and return last element
Array#push: adds one or more elements at the end
Array#shift: removes and return first element
Array#unshift: adds one or more elements at the beginning
For better visibillity, I replaced the null value with 1000, 2000, 3000 and 4000.
function shift(x, y) {
while (x > 0) {
chunks.forEach(function (a) {
a.pop();
a.unshift(1000);
});
x--;
}
while (x < 0) {
chunks.forEach(function (a) {
a.shift();
a.push(2000);
});
x++;
}
while (y > 0) {
chunks.unshift(chunks.pop().map(function () { return 3000; }));
y--;
}
while (y < 0) {
chunks.push(chunks.shift().map(function () { return 4000; }));
y++;
}
}
function print(msg) {
document.body.innerHTML += '<p>' + msg + '</p>';
}
function printarr(arr) {
for (var i = 0; i < arr.length; i++) {
print(JSON.stringify(arr[i]))
}
}
var chunks = [[5, 3, 1], [9, 2, 5], [2, 3, 7]];
print("chunks: " + JSON.stringify(chunks));
shift(1, 0);
print("shifting right 1. chunks: "); printarr(chunks);
shift(-1, 0);
print("shifting left 1. chunks: "); printarr(chunks);
shift(0, 1);
print("shifting up 1. chunks: "); printarr(chunks);
shift(0, -1);
print("shifting down 1. chunks: "); printarr(chunks);

You can use pop(), push(), shift(), unshift() Array methods
var chunks = [
[5, 3, 1],
[9, 2, 5],
[2, 3, 7]
];
function shiftDown(){
chuck.pop();
chuck.unshift(Array(3));
}
function shiftUp(){
chuck.shift();
chuck.push(Array(3));
}
function shiftRight(){
chuck.foreach(function(v){
v.pop();
v.unshift(null);
})
}
function shiftLeft(){
chuck.foreach(function(v){
v.shift();
v.push(null);
})
}

If interpret Question correctly, you can use Array.prototype.forEach(), Array.prototype.splice()
var chunks = [[5, 3, 1], [9, 2, 5], [2, 3, 7]];
// `x`: Index at which to start changing array
// `y`: An integer indicating the number of old array elements to remove
function shift(arr, x, y, replacement) {
arr.forEach(function(curr, index) {
// The elements to add to the array, beginning at the start index.
// start index: `x`
curr.splice(x, y, replacement)
});
return arr
}
// e.g.,
shift(chunks, -1, 1, null);
console.log(chunks);

it must call unloadChunk for elements that should be set to null
it's not a good idea to mutate an Array, while you're iterating over the same Array. So change unloadChunk() to not change chunks, but return the new value.
in my case I'm filling all the null values with new values.
then why do you bother to insert the null-values in the first place? why don't you just insert the new values?
//one-dimensional shift
function shift(arr, offset, callback){
var i, j, len = arr.length;
if(len && (offset |= 0)){
typeof callback === "function" || (callback = function(v){return v});
if(offset < 0){
for(i=-offset,j=0; i<len;)arr[j++]=arr[i++];
while(j<len)arr[j]=callback(null,j++,arr);
}else if(offset){
for(i=len-offset,j=len; i>0;)arr[--j]=arr[--i];
for(i=0; i<j;++i)arr[i]=callback(null,i,arr);
}
}
return arr;
}
//two dimensional shift
function shift2d(matrix, offsetX, offsetY, callback){
var i, len = matrix.length, tmp, fn;
offsetY |= 0;
offsetX |= 0;
if(len && matrix[0].length && (offsetY || offsetX)){
typeof callback === "function" || (callback = function(v){return v});
fn = function(val,j){ return callback(null, [i,j], matrix) };
tmp = {length: matrix[0].length};
offsetY && shift(matrix, offsetY, function(){return tmp});
for(i = 0; i < len; ++i){
if(matrix[i] === tmp){
matrix[i] = Array.from(tmp,fn);
}else{
shift(matrix[i], offsetX, fn);
}
}
}
return matrix;
}
and the code:
var chunks = [[5, 3, 1], [9, 2, 5], [2, 3, 7]];
console.log(chunks);
console.log(shift2d(chunks, -1, 1));
console.log(shift2d(chunks, 1, -1, computeValue));
function computeValue(value, index, array){
console.log("value: %o index: %o, is chunks: %o", value, index, array === chunks);
//return the new value for this field
return JSON.stringify(index);
return Math.random();
//with ES6 array destructuring:
var [row,col] = index;
return row*3 + col;
}
shift() and shift2d() expect as the last argument an (optional) callback function that returns the new values.
For consistency reasons, I pass the same argument as Array.map and the others
value: always null, only there for consistency reasons
index: the "index" that is accessed. For shift2d this is an array of indices (take a look at array destructuring)
array: the current array/matrix. Don't mess around with this while it gets changed. The main reason to pass this argument, is to check wich Array you're currently processing.

Related

finding a triplet in an array that sums up to a given value in javascript

I am trying to solve this problem in JavaScript:
Given an array and a value in JavaScript, find if there is a triplet in array whose sum is equal to the given value. If there is such a triplet present in array, then print the triplet and return true. Else return false.
Now, I wrote some code, and for some reason, it's not working properly.
Here is the code:
A = [1, 4, 45, 6, 10, 8];
sum = 15;
x = A.length;
function find3Numbers(A, x, sum) {
for (i=0; i<(x-2); i++) {
for (j=i+1; j<(x-1); j++) {
for (k=j+1; x; k++) {
if (A[i] + A[j] + A[k] == sum) {
console.log(A[i]);
console.log(A[j]);
console.log(A[k]);
return true
}
return false
}
}
}
}
console.log(find3Numbers(A, x, sum));
Now when I run the code, I get a "false" message.
Any idea, why is that?
You immediately return false if the first triplet you try does not match, when you should only do so after all loops have finished.
A = [1, 4, 45, 6, 10, 8];
sum = 15;
x = A.length;
function find3Numbers(A, x, sum) {
for (i = 0; i < (x - 2); i++) {
for (j = i + 1; j < (x - 1); j++) {
for (k = j + 1; x; k++) {
if (A[i] + A[j] + A[k] == sum) {
console.log(A[i]);
console.log(A[j]);
console.log(A[k]);
return true
}
}
}
}
return false;
}
console.log(find3Numbers(A, x, sum));
Consider sorting the array beforehand for O(n^2) time complexity rather than O(n^3).
Note: O(nlog(n) + n^2) is asymptotically the same as O(n^2).
const find3Numbers = (nums, nums_length, target) => {
nums.sort((a, b) => a - b);
let i = 0;
while (i < nums_length - 2) {
let j = i + 1;
let k = nums_length - 1;
while (j < k) {
curr_sum = nums[i] + nums[j] + nums[k];
if (curr_sum < target) {
j++;
while (j < k && nums[j] == nums[j - 1]) {
j++;
}
} else if (curr_sum > target) {
k--;
while (j < k && nums[k] == nums[k + 1]) {
k--;
}
} else {
return [nums[i], nums[j], nums[k]];
}
}
i++;
while (i < nums_length - 2 && nums[i] == nums[i - 1]) {
i++;
}
}
return [-1, -1, -1];
}
const A = [1, 4, 45, 6, 10, 8];
const x = A.length;
const sum = 15;
console.log(find3Numbers(A, x, sum));

Correct merge sort

So... If I input:
4 1 5 3
INSTEAD OF 1,3,4,5
I GET [ 4, 1, 5, 3 ]
Following is the code for merge sort but for the last comparison the program doesn't fetch updated (1,4) (3,5) value rather (4,1) (5,3) thus giving the wrong result.
var a = [4, 1, 5, 3];
q(a);
function q(a) {
var start = 0;
var n = a.length;
var length = parseInt(n / 2);
if (n < 2) {
return n;
}
var l = [], r = [];
for (i = 0; i < length; i++) {
l[i] = a[i]; //left array
}
for (i = 0, j = length; j < n; i++ , j++) {
r[i] = a[j]; //right array
}
q(l); //merge sort left array
q(r); //merge sort right array
comp(l, r);
}
function comp(l, r) {
var k = [], m = 0, i = 0, j = 0;
while (i < ((l.length)) && j < ((r.length))) {
if (l[i] < r[j]) {
k[m] = l[i];
i++;
m++
}
else {
k[m] = r[j];
j++;
m++
}
}
while (i != (l.length)) {
k[m] = l[i];
m++;
i++;
}
while (j != (r.length)) {
k[m] = r[j];
m++;
j++;
}
console.log(k); //for final output it is [ 4, 1, 5, 3 ] instead of [1,3,4,5]
}
You have a couple small problems. The main one is that you are returning the wrong thing from your edge condition:
if (n < 2) {
return n; // n is just a length; doesn't make sense to return it.
}
n is the length, you really want to return the small array here:
if (n < 2) {
return a; // return the array instead
}
Also, you need to pass the result of the recursive call to your comp function. Right now you're just returning the original lists with:
comp(l, r)
Something like this would work better:
let l_sort = q(l); //merge sort left array
let r_sort = q(r); //merge sort right array
return comp(l_sort, r_sort); // merge the arrays when recursion unwinds.
And you need to return things for recursion to work.
Put all together:
function q(a) {
var start = 0;
var n = a.length;
var length = parseInt(n / 2);
if (n < 2) {
return a;
}
var l = [],
r = [];
for (i = 0; i < length; i++) {
l[i] = a[i]; //left array
}
for (i = 0, j = length; j < n; i++, j++) {
r[i] = a[j]; //right array
}
let l_sort = q(l); //merge sort left array
let r_sort = q(r); //merge sort right array
return comp(l_sort, r_sort);
}
function comp(l, r) {
var k = [],
m = 0,
i = 0,
j = 0;
while (i < ((l.length)) && j < ((r.length))) {
if (l[i] < r[j]) {
k[m] = l[i];
i++;
m++
} else {
k[m] = r[j];
j++;
m++
}
}
while (i != (l.length)) {
k[m] = l[i];
m++;
i++;
}
while (j != (r.length)) {
k[m] = r[j];
m++;
j++;
}
return k
}
console.log(q([4, 1, 5, 3]).join(','));
console.log(q([5, 4, 3, 2, 1]).join(','));
console.log(q([2, 3]).join(','));
console.log(q([3, 2]).join(','));
console.log(q([1]).join(','));

Multiple array intersection in javascript

How to write in javascript(w/wth JQuery) to find values that intersect between arrays?
It should be like
var a = [1,2,3]
var b = [2,4,5]
var c = [2,3,6]
and the intersect function should returns array with value {2}. If possible it could applicable for any number of arrays.
Thanks
There are many ways to achieve this.
Since you are using jQuery I will suggest use grep function to filter the value that are present in all three array.
var a = [1, 2, 3]
var b = [2, 4, 5]
var c = [2, 3, 6]
var result = $.grep(a, function(value, index) {
return b.indexOf(value) > -1 && c.indexOf(value) > -1;
})
console.log(result)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Explanation: Loop over any array and filter out the values that are present in other array.
Update (for multimidensional array):
Concept - flatten the multidimensional array that is transform [[1,2],3,4] to [1,2,3,4] and then use the same logic used for single dimensional array.
Example:
var a = [
[1, 4], 2, 3
]
var b = [2, 4, 5]
var c = [2, 3, 6, [4, 7]]
//flatten the array's
//[1,4,2,3]
var aFlattened = $.map(a, function(n) {
return n;
})
//[2,4,5]
var bFlattened = $.map(b, function(n) {
return n;
})
//[2,3,6,4,7]
var cFlattened = $.map(c, function(n) {
return n;
})
var result = $.grep(aFlattened, function(value) {
return (bFlattened.indexOf(value) > -1 && cFlattened.indexOf(value) > -1);
});
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
// First this is how you declare an array
var a = [1,2,3];
var b = [2,4,5];
var c = [2,3,6];
// Second, this function should handle undetermined number of parameters (so arguments should be used)
function intersect(){
var args = arguments;
// if no array is passed then return empty array
if(args.length == 0) return [];
// for optimisation lets find the smallest array
var imin = 0;
for(var i = 1; i < args.length; i++)
if(args[i].length < args[imin].length) imin = i;
var smallest = Array.prototype.splice.call(args, imin, 1)[0];
return smallest.reduce(function(a, e){
for(var i = 0; i < args.length; i++)
if(args[i].indexOf(e) == -1) return a;
a.push(e);
return a;
}, []);
}
console.log(intersect(a, b, c));
First of all '{}' means Object in JavaScript.
Here is my suggestion.(this is another way of doing it)
// declarations
var a = [1,2,3];
var b = [2,4,5];
var c = [2,3,6];
// filter property of array
a.filter(function(val) {
if (b.indexOf(val) > -1 && c.indexOf(val) > -1)
return val;
});
what it does is it checks for each element in array 'a' and checks if that value is present in array 'b' and array 'c'. If it is true it returns the value. Simple!!!. The above code should work for String as well but it wouldn't work for IE < 9, so be careful.
// Intersecting 2 ordered lists of length n and m is O(n+m)
// This can be sped up by skipping elements
// The stepsize is determined by the ratio of lengths of the lists
// The skipped elements need to be checked after skipping some elements:
// In the case of step size 2 : Check the previous element
// In case step size>2 : Binary search the previously skipped range
// This results in the best case complexity of O(n+n), if n<m
// or the more propable complexity of O(n+n+n*log2(m/n)), if n<m
function binarySearch(array, value, start = 0, end = array.length) {
var j = start,
length = end;
while (j < length) {
var i = (length + j - 1) >> 1; // move the pointer to
if (value > array[i])
j = i + 1;
else if (value < array[i])
length = i;
else
return i;
}
return -1;
}
function intersect2OrderedSets(a, b) {
var j = 0;
var k = 0;
var ratio = ~~(b.length / a.length) - 1 || 1;
var result = [];
var index;
switch (ratio) {
case 1:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k++;
if (k >= b.length) break;
}
}
break;
case 2:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k += 2;
if (k - 1 >= b.length) break;
if (a[j] <= b[k - 1]) k--;
}
}
break;
default:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k += ratio;
index = binarySearch(b, a[j], k - ratio + 1, k + 1 < b.length ? k + 1 : b.length - 1);
if (index > -1) {
result.push(a[j]);
j++;
k = index + 1;
} else {
j++;
k = k - ratio + 1;
}
if (k >= b.length) break;
}
}
}
return result;
}
function intersectOrderedSets() {
var shortest = 0;
for (var i = 1; i < arguments.length; i++)
if (arguments[i].length < arguments[shortest].length) shortest = i;
var result = arguments[shortest];
for (var i = 0, a, b, j, k, ratio, index; i < arguments.length; i++) {
if (result.length === 0) return result;
if (i === shortest) continue;
a = result;
b = arguments[i];
result = intersect2OrderedSets(a, b);
}
return result;
}
How to use:
intersectOrderedSets(a,b,c);

JavaScript Quicksort recursive

I´m trying to implement a quicksort algorithm for an int array in JavaScript.
I´ve got a problem in my code. The first few ints get sorted well but at the end of the sortet array there is always one integer which is placed many times although its only one time in the array which should be sorted. Hopefully someone will find my fault.
Thanks.
function quicksort(array) {
var randomPlace = Math.round(Math.random() * array.length);
var pivotelement = array[randomPlace];
left = new Array;
right = new Array;
for (var i = 0; i < array.length; i++) {
if (array[i] < pivot) {
left[left.length] = array[i];
} else {
right[right.length] = array[i];
}
}
if ((left.length == 0 || left.length == 1) && (right.length == 0 || right.length == 1)) {
return left.concat(right);
} else if (left.length == 0 || left.length == 1) {
return (left.concat((quicksort(right))));
} else if (right.length == 0 || right.length == 1) {
return ((quicksort(left)).concat(right));
} else {
return (quicksort(left)).concat((quicksort(right)));
}
}
Beside some nameming confusion, like pivotelement vs pivot and Math.round vs Math.floor, you need to tackle the problem of for example [1, 1, 1] which is always returning left = [] and right = [1, 1, 1], that calls quicksort([1, 1, 1]) ad infinitum.
To overcome this problem, you need to check for empty left and with right every element, if it is equal to the random pivot. Then return right, without calling quicksort again.
function quicksort(array) {
var randomPlace = Math.floor(Math.random() * array.length),
pivot = array[randomPlace],
left = [],
right = [],
i;
for (i = 0; i < array.length; i++) {
(array[i] < pivot ? left : right).push(array[i]);
}
console.log(pivot, JSON.stringify(array), JSON.stringify(left), JSON.stringify(right));
// prevent looping forever
if (!left.length && right.every(function (v) { return v === pivot; })) {
return right;
}
if (left.length <= 1 && right.length <= 1) {
return left.concat(right);
}
if (left.length <= 1) {
return left.concat(quicksort(right));
}
if (right.length <= 1) {
return quicksort(left).concat(right);
}
return quicksort(left).concat(quicksort(right));
}
console.log(quicksort([2, 7, 4, 8, 3, 11, 49, 20, 10, 1, 1, 1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another solution would be to separate the array into three arrays, one for smaller values, one for equal values and one for greater values. Then sort only the smaller and greater arrays.
function quicksort(array) {
var randomPlace = Math.floor(Math.random() * array.length),
pivotValue = array[randomPlace],
left = [],
pivot = [],
right = [],
i;
for (i = 0; i < array.length; i++) {
if (array[i] === pivotValue) {
pivot.push(array[i]);
continue;
}
(array[i] < pivotValue ? left : right).push(array[i]);
}
console.log(pivotValue, JSON.stringify(array), JSON.stringify(left), JSON.stringify(pivot), JSON.stringify(right));
if (left.length <= 1 && right.length <= 1) {
return left.concat(pivot, right);
}
if (left.length <= 1) {
return left.concat(pivot, quicksort(right));
}
if (right.length <= 1) {
return quicksort(left).concat(pivot, right);
}
return quicksort(left).concat(pivot, quicksort(right));
}
console.log(quicksort([2, 7, 4, 8, 3, 11, 49, 20, 10, 1, 1, 1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
heres a short version of quick sort written in JS exactly as it is seen in Intro To Algorithms, hope this helps!
var partition = function (arr, low, high) {
var x = arr[high]
var i = low - 1
for (var j = low; j <= high - 1; j++) {
if (arr[j] <= x) {
i++
var temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
}
var temp = arr[i + 1]
arr[i + 1] = arr[high]
arr[high] = temp
return i + 1
}
var quickSort = function (arr, low, high) {
if (low < high) {
index = partition(arr,low,high)
if (low < index-1) quickSort(arr,low,index-1)
if (index+1 < high) quickSort(arr,index+1,high)
}
}
var list2 = [1000,13,12,1001,82,1,2,4,3,0]
console.log(quickSort(list2,0,list2.length))
also on my GitHub
I think you are identifying the randomPlace wrongly. It returns undefined some times because you're using Math.round().
Try this instead:
var randomPlace = Math.floor(Math.random() * array.length);
Also, use the following code when initializing left, and right:
var left = new Array();
var right = new Array();
Also, you need to change the pivot in array[i] < pivot to pivotElement.
You can see my complete fiddle here

Pair of elements from a specified array whose sum equals a specific target number

I am in mid of my JavaScript session. Find this code in my coding exercise. I understand the logic but I didn't get this map[nums[x]] condition.
function twoSum(nums, target_num) {
var map = [];
var indexnum = [];
for (var x = 0; x < nums.length; x++)
{
if (map[nums[x]] != null)
// what they meant by map[nums[x]]
{
index = map[nums[x]];
indexnum[0] = index+1;
indexnum[1] = x+1;
break;
}
else
{
map[target_num - nums[x]] = x;
}
}
return indexnum;
}
console.log(twoSum([10,20,10,40,50,60,70],50));
I am trying to get the Pair of elements from a specified array whose sum equals a specific target number. I have written below code.
function arraypair(array,sum){
for (i = 0;i < array.length;i++) {
var first = array[i];
for (j = i + 1;j < array.length;j++) {
var second = array[j];
if ((first + second) == sum) {
alert('First: ' + first + ' Second ' + second + ' SUM ' + sum);
console.log('First: ' + first + ' Second ' + second);
}
}
}
}
var a = [2, 4, 3, 5, 6, -2, 4, 7, 8, 9];
arraypair(a,7);
Is there any optimized way than above two solutions? Can some one explain the first solution what exactly map[nums[x]] this condition points to?
Using HashMap approach using time complexity approx O(n),below is the following code:
let twoSum = (array, sum) => {
let hashMap = {},
results = []
for (let i = 0; i < array.length; i++){
if (hashMap[array[i]]){
results.push([hashMap[array[i]], array[i]])
}else{
hashMap[sum - array[i]] = array[i];
}
}
return results;
}
console.log(twoSum([10,20,10,40,50,60,70,30],50));
result:
{[10, 40],[20, 30]}
I think the code is self explanatory ,even if you want help to understand it,let me know.I will be happy enough to for its explanation.
Hope it helps..
that map value you're seeing is a lookup table and that twoSum method has implemented what's called Dynamic Programming
In Dynamic Programming, you store values of your computations which you can re-use later on to find the solution.
Lets investigate how it works to better understand it:
twoSum([10,20,40,50,60,70], 50)
//I removed one of the duplicate 10s to make the example simpler
In iteration 0:
value is 10. Our target number is 50. When I see the number 10 in index 0, I make a note that if I ever find a 40 (50 - 10 = 40) in this list, then I can find its pair in index 0.
So in our map, 40 points to 0.
In iteration 2:
value is 40. I look at map my map to see I previously found a pair for 40.
map[nums[x]] (which is the same as map[40]) will return 0.
That means I have a pair for 40 at index 0.
0 and 2 make a pair.
Does that make any sense now?
Unlike in your solution where you have 2 nested loops, you can store previously computed values. This will save you processing time, but waste more space in the memory (because the lookup table will be needing the memory)
Also since you're writing this in javascript, your map can be an object instead of an array. It'll also make debugging a lot easier ;)
function twoSum(arr, S) {
const sum = [];
for(let i = 0; i< arr.length; i++) {
for(let j = i+1; j < arr.length; j++) {
if(S == arr[i] + arr[j]) sum.push([arr[i],arr[j]])
}
}
return sum
}
Brute Force not best way to solve but it works.
Please try the below code. It will give you all the unique pairs whose sum will be equal to the targetSum. It performs the binary search so will be better in performance. The time complexity of this solution is O(NLogN)
((arr,targetSum) => {
if ((arr && arr.length === 0) || targetSum === undefined) {
return false;
} else {
for (let x = 0; x <=arr.length -1; x++) {
let partnerInPair = targetSum - arr[x];
let start = x+1;
let end = (arr.length) - 2;
while(start <= end) {
let mid = parseInt(((start + end)/2));
if (arr[mid] === partnerInPair) {
console.log(`Pairs are ${arr[x]} and ${arr[mid]} `);
break;
} else if(partnerInPair < arr[mid]) {
end = mid - 1;
} else if(partnerInPair > arr[mid]) {
start = mid + 1;
}
}
};
};
})([0,1,2,3,4,5,6,7,8,9], 10)
function twoSum(arr, target) {
let res = [];
let indexes = [];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (target === arr[i] + arr[j] && !indexes.includes(i) && !indexes.includes(j)) {
res.push([arr[i], arr[j]]);
indexes.push(i);
indexes.push(j);
}
}
}
return res;
}
console.log('Result - ',
twoSum([1,2,3,4,5,6,6,6,6,6,6,6,6,6,7,8,9,10], 12)
);
Brute force.
const findTwoNum = ((arr, value) => {
let result = [];
for(let i= 0; i< arr.length-1; i++) {
if(arr[i] > value) {
continue;
}
if(arr.includes(value-arr[i])) {
result.push(arr[i]);
result.push(value-arr[i]);
break;;
}
}
return result;
});
let arr = [20,10,40,50,60,70,30];
const value = 120;
console.log(findTwoNum(arr, value));
OUTPUT : Array [50, 70]
function twoSum(arr){
let constant = 17;
for(let i=0;i<arr.length-2;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[i]+arr[j] === constant){
console.log(arr[i],arr[j]);
}
}
}
}
let myArr = [2, 4, 3, 5, 7, 8, 9];
function getPair(arr, targetNum) {
for (let i = 0; i < arr.length; i++) {
let cNum = arr[i]; //my current number
for (let j = i; j < arr.length; j++) {
if (cNum !== arr[j] && cNum + arr[j] === targetNum) {
let pair = {};
pair.key1 = cNum;
pair.key2 = arr[j];
console.log(pair);
}
}
}
}
getPair(myArr, 7)
let sumArray = (arr,target) => {
let ar = []
arr.forEach((element,index) => {
console.log(index);
arr.forEach((element2, index2) => {
if( (index2 > index) && (element + element2 == target)){
ar.push({element, element2})
}
});
});
return ar
}
console.log(sumArray([8, 7, 2, 5, 3, 1],10))
Use {} hash object for storing and fast lookups.
Use simple for loop so you can return as soon as you find the right combo; array methods like .forEach() have to finish iterating no matter what.
And make sure you handle edges cases like this: twoSum([1,2,3,4], 8)---that should return undefined, but if you don't check for !== i (see below), you would erroneously return [4,4]. Think about why that is...
function twoSum(nums, target) {
const lookup = {};
for (let i = 0; i < nums.length; i++) {
const n = nums[i];
if (lookup[n] === undefined) {//lookup n; seen it before?
lookup[n] = i; //no, so add to dictionary with index as value
}
//seen target - n before? if so, is it different than n?
if (lookup[target - n] !== undefined && lookup[target - n] !== i) {
return [target - n, n];//yep, so we return our answer!
}
}
return undefined;//didn't find anything, so return undefined
}
We can fix this with simple JS object as well.
const twoSum = (arr, num) => {
let obj = {};
let res = [];
arr.map(item => {
let com = num - item;
if (obj[com]) {
res.push([obj[com], item]);
} else {
obj[item] = item;
}
});
return res;
};
console.log(twoSum([2, 3, 2, 5, 4, 9, 6, 8, 8, 7], 10));
// Output: [ [ 4, 6 ], [ 2, 8 ], [ 2, 8 ], [ 3, 7 ] ]
Solution In Java
Solution 1
public static int[] twoNumberSum(int[] array, int targetSum) {
for(int i=0;i<array.length;i++){
int first=array[i];
for(int j=i+1;j<array.length;j++){
int second=array[j];
if(first+second==targetSum){
return new int[]{first,second};
}
}
}
return new int[0];
}
Solution 2
public static int[] twoNumberSum(int[] array, int targetSum) {
Set<Integer> nums=new HashSet<Integer>();
for(int num:array){
int pmatch=targetSum-num;
if(nums.contains(pmatch)){
return new int[]{pmatch,num};
}else{
nums.add(num);
}
}
return new int[0];
}
Solution 3
public static int[] twoNumberSum(int[] array, int targetSum) {
Arrays.sort(array);
int left=0;
int right=array.length-1;
while(left<right){
int currentSum=array[left]+array[right];
if(currentSum==targetSum){
return new int[]{array[left],array[right]};
}else if(currentSum<targetSum){
left++;
}else if(currentSum>targetSum){
right--;
}
}
return new int[0];
}
function findPairOfNumbers(arr, targetSum) {
var low = 0, high = arr.length - 1, sum, result = [];
while(low < high) {
sum = arr[low] + arr[high];
if(sum < targetSum)
low++;
else if(sum > targetSum)
high--;
else if(sum === targetSum) {
result.push({val1: arr[low], val2: arr[high]});
high--;
}
}
return (result || false);
}
var pairs = findPairOfNumbers([1,2,3,4,4,5], 8);
if(pairs.length) {
console.log(pairs);
} else {
console.log("No pair of numbers found that sums to " + 8);
}
Simple Solution would be in javascript is:
var arr = [7,5,10,-5,9,14,45,77,5,3];
var arrLen = arr.length;
var sum = 15;
function findSumOfArrayInGiven (arr, arrLen, sum){
var left = 0;
var right = arrLen - 1;
// Sort Array in Ascending Order
arr = arr.sort(function(a, b) {
return a - b;
})
// Iterate Over
while(left < right){
if(arr[left] + arr[right] === sum){
return {
res : true,
matchNum: arr[left] + ' + ' + arr[right]
};
}else if(arr[left] + arr[right] < sum){
left++;
}else{
right--;
}
}
return 0;
}
var resp = findSumOfArrayInGiven (arr, arrLen, sum);
// Display Desired output
if(resp.res === true){
console.log('Matching Numbers are: ' + resp.matchNum +' = '+ sum);
}else{
console.log('There are no matching numbers of given sum');
}
Runtime test JSBin: https://jsbin.com/vuhitudebi/edit?js,console
Runtime test JSFiddle: https://jsfiddle.net/arbaazshaikh919/de0amjxt/4/
function sumOfTwo(array, sumNumber) {
for (i of array) {
for (j of array) {
if (i + j === sumNumber) {
console.log([i, j])
}
}
}
}
sumOfTwo([1, 2, 3], 4)
function twoSum(args , total) {
let obj = [];
let a = args.length;
for(let i = 0 ; i < a ; i++){
for(let j = 0; j < a ; j++){
if(args[i] + args[j] == total) {
obj.push([args[i] , args[j]])
}
}
}
console.log(obj)}
twoSum([10,20,10,40,50,60,70,30],60);
/* */

Categories

Resources