Know the last number equal to another within an array in Javascript - javascript

const numbersArray = [5, 3, 1, 3, 4, 5, 3, 1];
var pastNumbers = [];
for (let i = 0; i < numbersArray.length; i++) {
const number = numbersArray[i];
pastNumbers.push(number);
var count = 0;
pastNumbers.forEach((v) => (v === number && count++));
console.log(`There are ${count} numbers before equal to ${number}. The last equal number is in the ${???} position.`);
}
I have an array called pastNumbers that stores the numbers that were previously traversed by the for loop of another array called numbersArray. Then with forEach I get the amount of previous numbers equal to number.
I want to know the position of the last number equal to number within the pastNumbers array.
How can I do it?

Updated with for loop
Use an object instead of array to track, it makes it a bit easier.
In this example, I'm going over each number and adding the position at the beginning (unshift) to pastNumber[number].
I'm using unshift so that the first item is the last position registred. That way I can look up with [0] instead of using [$.length-1] (but I'm still still using the length anyway so you push is fine too 🤷‍♂️)
const numbersArray = [5, 3, 1, 3, 4, 5, 3, 1];
const pastNumbers = {};
for (let i = 0; i < numbersArray.length; i++) {
const number = numbersArray[i];
if (!pastNumbers[number]) {
pastNumbers[number] = [];
}
if (pastNumbers[number].length > 0) {
console.log(
`There are ${pastNumbers[number].length} numbers before equal to ${number}. The last equal number is in the ${pastNumbers[number][0]} position.`
);
}
pastNumbers[number].unshift(i);
}

Related

How can I decrease the time spent checking each value in this leetcode?

So on LeetCode, I need to return the sum of two numbers that equal the target number. This is a leetcode "easy" type. I've never done leetcode before so I decided to give it a try. Right off the bat, I was able to solve the problem but my solution was nonsenical because it checks each number in the array against eachother. So if the input is a million digits then it will check it a million times for each number.
It's worth noting that although my program works, it can be submitted due to time limit exceeding.
I'm not sure what the mathematical solution would be to opitmize this. I'm currently going to Maths again learning what I am weak at.
Code:
var twoSum = function(nums, target) {
let total = [];
let inc = 1;
let intVal = 0;
let startingPos = nums[intVal];
let nextPos = nums[inc];
for(let x = 0; x < nums.length; x++){
// Do not check the value of position 1 with position 2
if(nums.indexOf(startingPos) === nums.lastIndexOf(nextPos)){
nextPos++;
}
if(startingPos + nextPos === target){
console.log(`First Value ${startingPos}`)
console.log(`Second Value ${nextPos}`)
console.log(`Target ${target}`)
// A match has been found
return [nums.indexOf(startingPos), nums.lastIndexOf(nextPos)];
} else{
// Move to next number if index 1 is not eql
// nextPos++;
let nextPosIndex = nums[inc];
nextPos = nums[inc];
console.log(`Values [${startingPos}], [${nextPos}]`)
console.log("No Matches");
// Increment the next value to check
inc++;
// Reset loop if no match is found from 2nd position
if(x == (nums.length - 1)){
// Increment the initial value in first pos
intVal++;
startingPos = nums[intVal];
// Reset values to check new numbers
x = 0;
inc = 1;
}
// check if we exhausted all options
if(startingPos === undefined){
return "No Matches.";
}
}
}
};
twoSum([5, 2, 5, 5, 1, 3, 6, 8, 4, 3, 2, 7], 14)
--
Before proceeding to any more problems, I am afraid I will be in this loop of choosing the most illogical way of solving the problems.
What can I do to modify this problem to quickly check if two values equals the target.
Here is a live compiler example: https://replit.com/#FPpl/SafeHeartfeltArchitect#index.js
When iterating over a number, you can put the value that, if it would match to sum to the target, into a collection (with O(1) lookup). For example, if you iterate over a number 5, and the target is 20, put 15 into the collection.
During an iteration, if the number being iterated over already exists in the collection, you have a match from one you found previously, and you can return both indicies.
const twoSum = function(nums, target) {
// For this Map, the key is the number which, if found again, is a match
// eg, if target is 20, and the number 5 is iterated over
// the key will be 15
// The value is the index of the prior number found - eg, index of 5
const valuesAlreadyFound = new Map();
for (let i = 0; i < nums.length; i++) {
const num = nums[i];
if (valuesAlreadyFound.has(num)) {
// We have a match, get both indicies:
console.log('Match for values', target - num, num);
return [valuesAlreadyFound.get(num), i];
}
// This wasn't a match. Identify the number which, when paired, is a match
const matchNeeded = target - num;
valuesAlreadyFound.set(matchNeeded, i);
}
return 'No match';
};
console.log('Indicies found:', twoSum([5, 2, 5, 5, 1, 3, 6, 8, 4, 3, 2, 7], 14));

Given an array of numbers, return an array of numbers which contains 1st number, Sum of next 2 numbers (2nd, 3rd), Sum of next 3 numbers(4th,5th,6th)

Given an array of numbers, return an array of numbers which contains 1st number, Sum of next 2 numbers (2nd, 3rd), Sum of next 3 numbers(4th,5th,6th)
let num = [1, 5, 7, 2, 4, 9];
let result = [];
function sumOfIntegers(num) {
result.push(num[0]);
for(let i=1; i<num.length; i=i+3){
let prevNum1 = num [i]
let prevNum2 = num [i+1]
result.push(prevNum1 + prevNum2);
}
//console.log(result);
return result[];
}
sumOfIntegers(num);
This is the way I would have done it in js:
let num = [1, 5, 7, 2, 4, 9];
function sumOfIntegers(num) {
let result = [];
for(i=0; i<num.length; i++){
sum = 0
for(j=0; j<=i; j++){
sum += num[j]
}
result.push(sum)
}
return result;
}
console.log(sumOfIntegers(num));
The way I thought of this is that you want to accumulate all the integers in the list from the first point (index 0) to the point where you currently are, iterating through the whole list again. Therefore two nested for-loops. The magic is in the dynamic approach, as this will be the same no matter how many numbers your num-array is filled with.

Sequence in an array

I have an algo exercise to do and I have no idea how to do it, as the requirement is to use only basic programming concepts. So - the point is to find the longest sequence of numbers in an array that are growing or not changing value.
So for the array [1,1,2,4,0,1,7,4], it would be [1,1,2,4].
It should have as small time and memory complexity as possible. Any solutions, tips? Much love and thanks in advance for any advice or feedback.
That's what I've managed to do in the last 10 minutes, but I feel like I'm doing it in the most complex way possible...
function idk(array) {
var current = 0;
var winner = 0;
var currentArray = [];
var winnerArray = [];
for (let i = 0; i <= array.length; i++) {
if (array[i + 1] >= array[i]) {
currentArray.push(array[i]);
current = currentArray.length;
} else {
currentArray.push(array[i]);
if (currentArray.length > best.length) {
// copy array and append it to the new array?
}
}
}
return winnerArray;
}
Try this javascript algorithm:
var array = [1, 8, 1, 1, 5, 7, 2, 2]
var output = []
array.forEach(function(value, index) {
if (array[index - 1] <= value && index != 0) {
output[output.length - 1].push(value)
} else {
output.push([value])
}
})
var longestArray = []
output.forEach(function(arrayCompare, index) {
if (arrayCompare.length > longestArray.length || index == 0) {
longestArray = arrayCompare
}
})
console.log(longestArray)
The first forEach loops through the elements of array. If the element is larger than or equal to the previous element, it adds it to the last array in output. If it is not, then it creates a new array, and pushes the array into output. This creates arrays with "growing" sequences.
After that, it loops through each sequence, and checks if the length of the sequence is greater than the current longest sequence, which is stored in longestArray. If it is, it changes longestArray to that. If it isn't, it does nothing.
Note that both of these loops have exceptions if the index is 0, since there is no element with index -1 (therefore such an exception had to be made).
Also, here's the same implementation in python:
array = [1, 8, 1, 1, 5, 7, 2, 2]
output = []
index = 0
while index < len(array):
value = array[index]
if (array[index-1] <= value and index !=0):
output[-1].append(value)
else:
output.append([value])
index += 1
longestArray = []
index = 0
while index < len(output):
arrayCompare = output[index]
if index==0 or len(arrayCompare) > len(longestArray):
longestArray = arrayCompare
index += 1
print(longestArray)
Just why loop over the end of the array?
Because you could take this advantage to gather the last longest sequence without having a check after the loop for having found a longest sequence.
But in parts:
Why not a temporary array? Because there is no need to use it, if you collect the values. the startignn index of a sequence is important and the actual indec to decide if the sequence is longer then the previously found one.
The loop feature two conditions, one for continuing the loop, if in sequence and another to check if the actual ended sequence is longer. And for storing the actual index.
The last loop with a check for an undefined value is false, it does not continue the loop and the nect check reveals either a new longest sequence or not.
Some other annotation:
winnerArray has to be an empty array, because of the check later for length
The sequence check take the previous element, because the loop starts with the first index and the previous element is given.
The Big O is O(n).
function idk(array) {
let winnerArray = [],
index = 0;
for (let i = 1; i < array.length + 1; i++) {
if (array[i - 1] <= array[i]) continue;
if (i - index > winnerArray.length) winnerArray = array.slice(index, i);
index = i;
}
return winnerArray;
}
console.log(...idk([1, 1, 2, 4, 0, 1, 7, 4])); // [1, 1, 2, 4]
console.log(...idk([1, 8, 1, 1, 5, 7, 2, 2])); // [1, 1, 5, 7]
console.log(...idk([1, 8, 1, 1, 5, 7, 2, 2, 2, 2, 2]));
Here is the dynamic programming algorithm in Python:
def longest_sequence(numbers):
length = len(numbers)
L = [0] * length #L stores max possible lengths at each index
L[-1] = 1 # base case
for i in range(length-2, -1, -1):
max_length = L[i]
for j in range(i, length):
if (L[j] > max_length) and (numbers[j] > numbers[i]):
max_length = L[j]
L[i] = max_length + 1
#trace back
max_length = max(L)
result = []
for k in range(max_length, 0, -1):
result.append(numbers[L.index(k)])
numbers = numbers[L.index(k):]
L = L[L.index(k):]
return result
my_numbers = [36,13,78,85,16,52,58,61,63,83,46,19,85,1,58,71,26,26,21,31]
print(longest_sequence(my_numbers))
#>>[13, 16, 52, 58, 61, 63, 83, 85]
To be optimal, you should not use intermediate lists during processing. You only need to hold indexes, sizes and the previous value:
def longSeq(A):
longStart,longSize = 0,0 # best range so far (index and size only)
start,size,prev = 0,0,None # current range (index and size)
for i,a in enumerate(A):
if i == 0 or prev <= a: # increase current range
size += 1
prev = a
if size > longSize: # track longest so far
longStart,longSize = start,size
else:
start,size,prev = i,1,a # sequence break, restart current
return A[longStart:longStart+longSize]
output:
print(longSeq([1,1,2,4,0,1,7,4])) # [1, 1, 2, 4]
print(longSeq( [1,8,1,1,5,7,2,2])) # [1, 1, 5, 7]
This will perform in O(n) time and use O(1) space.

Split array into arrays of numbers where the sum is equal to a specific target

I need to create a function that take as parameter an array and a target. It should return an array of arrays where the sum of these numbers equals to the target
sumPairs(array, target) {
}
For example:
sumPairs([1, 2, 3, 4, 5], 7) // output : [[2, 5], [3, 4]]
I know I have to use map(), and probably reduce(), set(), or filter() maybe (I read their documentation in MDN but still cant find out). I tried some ways but I can't get it.
If you guys could help me to find out how to dynamically create arrays and push them into a new array..
I read there some solutions (Split array into arrays of matching values) but I hate to just use created functions without knowing what they really do or how they work.
Some very basic code for achieving it, Just run all over combinations and conditionally add the items you want.
function sumPairs(array, target) {
var res = [];
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array.length; j++){
if(i!=j && array[i]+array[j]==target &&
res.filter((x)=> x[0] == array[j] && x[1] == array[i]).length == 0 )
res.push([array[i], array[j]]);
}
}
return res;
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
Option 2 - see this answer for more options (like using reduce)
function sumPairs(array, target) {
return array.flatMap(
(v, i) => array.slice(i+1).filter(w => (v!=w && v+w==target)).map(w=> [w,v])
);
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
"The exercise says that it sould be arrays of pairs that sum the
target value so I think only 2 items"
If you need a pair that matches a sum and you pick any number from the list, you are left with
the following equation to solve num + x = sum where we want to find x. E.g. if you picked 7 and the target sum is 10 then you know you are looking for a 3.
Therefore, we can first construct a counting map of the numbers available in our list linear (O(n)) time and then search for matches in linear time as well rather than brute forcing with a quadratic algorithm.
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
return nums.reduce((pairs, num) => {
countByNum[num]--;
const target = sum - num;
if (countByNum[target] > 0) {
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[num]++;
}
return pairs;
}, []);
}
function countGroupByNum(nums) {
return nums.reduce((acc, n) => (acc[n] = (acc[n] || 0) + 1, acc), {});
}
Here's another implementation with more standard paradigms (e.g. no reduce):
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
const pairs = [];
for (const num of nums) {
const target = sum - num; //Calculate the target to make the sum
countByNum[num]--; //Make sure we dont pick the same num instance
if (countByNum[target] > 0) { //If we found the target
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[target]++; //Didin't find a match, return the deducted num
}
}
return pairs;
}
function countGroupByNum(nums) {
const countByNum = {};
for (const num of nums) {
countByNum[num] = (countByNum[num] || 0) + 1;
}
return countByNum;
}
You can also sort your array and find all the pairs with given sum by using two pointer method. Place the first pointer to the start of the array and the second pointer to the end.
if the sum of the values at the two places is :
More than target: Decrement your second pointer by 1
Less than target: Increment your first pointer by 1
Equal to target: This is one possible answer, push them to your answer array and increment your first pointer by 1 and decrement your second pointer by 1.
This is more performant solution with complexity O(n*log(n))

For Loop that calculates sum of squred numbers in array

I am working on a challenge and in need of some help:
Write a for loop that calculates sum of squares of items in an array of numbers. Example: For array [ 1, 2, 3, 4 ] it calculates the sum of squares as 30 (i.e. 1 + 4 + 9 + 16). I have a fiddle set up if anyone wants to have a closer look. Thanks for your help!
https://jsfiddle.net/jamie_shearman/2drt56e3/23/
var aFewNumbers = [ 1, 2, 3, 7 ];
var squareOfAFewNumbers = 0;
for( var i = 0; i <= aFewNumbers; i++ ) {
squareOfAFewNumbers = squareOfAFewNumbers * aFewNumbers[i] ;
}
console.log( squareOfAFewNumbers );
Your math is wrong. As an obvious issue, the variable starts at 0 and then is multiplied by each array element; 0 times anything is 0, so it will always remain 0 no matter what the values are. Not to mention your loop isn't looking at the length of the array as a stopping condition, which it should be, since you want to iterate from the beginning to the end of the array.
You need to iterate through to the array's length, square each array element, and add that square to the variable:
for( var i = 0; i < aFewNumbers.length; i++ ) {
squareOfAFewNumbers += aFewNumbers[i] * aFewNumbers[i];
}
If you can use ES6, you can even use higher-order array functions to simplify this more:
var squareOfAFewNumbers = aFewNumbers.reduce((result, entry) => result + entry * entry, 0);
There are multiple approaches you can take for reaching the desired result, but as you've mentioned that you must write a for loop; therefore, I sorted the answers by having that in mind.
Using the for loop
let numbers = [1, 2, 3, 7],
sum = 0;
for(let i = 0; i < numbers.length; i++) {
sum += Math.pow(numbers[i], 2)
}
// Sum is now 63
Using forEach method of the array object
let numbers = [1, 2, 3, 7],
sum = 0;
numbers.forEach(number => sum += Math.pow(number, 2))
// Sum is now 63
Oneliner
let sum = [1, 2, 3, 7].reduce((a, c) => a + Math.pow(c, 2))
The reduce method uses an accumulator to store temporary results, the accumulator is passed to the callback as the first argument and the second argument is the element's value, you can read more about the reduce method here.
You can use JavaScript pow() Method to create the square and sum it to the sumSquareOfAFewNumbers.
var aFewNumbers = [ 1, 2, 3, 7 ];
var sumSquareOfAFewNumbers = 0;
aFewNumbers.forEach(function(element) {
sumSquareOfAFewNumbers += Math.pow(element, 2);
});
console.log(sumSquareOfAFewNumbers)

Categories

Resources