I have tried to calculate binary of a number provided in an array using naive for-loop method.
Than I find a solution which works but I am not able to understand how it is working.
I need help to understand this.
const binaryArrayToNumber = arr => {
return arr.reduce((a,b)=>(a<<1|b),0);
};
console.log(binaryArrayToNumber([1,1,1,1]))
Explaining your code:
The << left logical shift) shifts the number to the left. If the number n is 00010110 then:
n << 1 will be 00101100.
n << 2 will be 01011000.
etc
The operator | (betwise or) performs an iclusive logical OR on the bits at the same positions. If the numbers n and m were, respectively 00110100 and 10010101 then:
n = 00110100
m = 10010101
----------------
n | m = 10110101
following these rules: 0 | 0 = 0, 0 | 1 = 1, 1 | 0 = 1 and 1 | 1 = 1.
Now for the reduce part: reduce loop through an array, passing an accumulator (initially set by the user, the last parameter) and the current item of the array to a callback (the function passed as the first parameter) and set the value of the accumulator to the returned value of that callback.
So for each item in the array we shifts the accumulator to the left to make a place for the new bit and then add the bit to that place using the betwise or. Here is an example with explanation:
var arr = [1, 0, 1];
reduce will start with an accumulator equal to 0 (...,0); at end of reduce line) then pass it along with the current item (the first item) to the callback. The the callback will shift the accumulataror (a) to the left by 1:
First shift the accumulator:
a = 00000000;
a << 1 = 00000000;
And then return the betwise or result of the shifted a with the current item from the array b:
b = 00000001;
00000000 | b = 00000001;
Now the new accumulator is the result of the above code (00000001).
reduce then will pass the current accumulator along with the current item from the array (now the second one) to the callback again:
First:
a = 00000001;
a << 1 = 00000010;
and:
b = 00000000;
00000010 | b = 00000010;
reduce will do the same thing for the last item of the array:
First:
a = 00000010;
a << 1 = 00000100;
and:
b = 00000001;
00000100 | 00000001 = 00000101;
Since there is no more items in the array, reduce will return the accumulated value (the accumulator return by the last call to the callback i.e a) as the result.
If the syntax return arr.reduce((a,b)=>(a<<1|b),0); isn't clear for you, it's because you're not familliar with Arrow functions. The exact line could be written using regular functions like this:
return arr.reduce(function(a, b) { // a the accumulator, b the curent item from the array
return (a << 1) | b; // return something to store as the new accumulator
}, 0; // 0 is the initial value of the accumulator
Another way to do it:
without using any binary operation nor reduce:
var arr = [1, 0, 1, 1];
var number = parseInt(arr.join(''), 2);
console.log(number);
arr.join('') will return a string (a concatenation of all the items in the array "1011"). Then parseInt will parse that string as being a binary number.
The reduce function works as an accumulator. The (a,b) pair is actually (total, currentValue). For instance, if you want to calculate sum of 1, 2 and 3, you can use the following code for that:
var sum = [1, 2, 3].reduce(
function(total, currentNumber){ return total + currentNumber; }
, 0);
For each iteration, a value of the total variable is increased for currentNumber and after all elements of the array were iterated, the total is being assigned to the sum variable.
The second parameter of the anonymous function (in this case 0) is the initial value of the sum (before iterating the array elements).
So, the code above is same as this code:
var sum = 0;
for (var i = 1; i <=3; i++)
{
sum = sum + i;
}
Related
The solution that i've been working on so far:
function solution(elements) {
let numOfShifts;
let shift = shiftedArray(elements);
for(i = 0; i < shift.length; i++){
//Here is where i'm getting stuck... how do i continue through the loop even after the first false is returned
//until all arrays are checked for equality?
if(areEqual(shift[i])){
numOfShifts = i
}else return -1;
}
return numOfShifts;
};
function shiftedArray(array){
let shiftedArrays = [];
for(let i = array.length -1 ; i >= 1; i--){
// first element is simply a formula to create chunk 1
let firstElement = array.length - (i % array.length);
//the result of first element.
let chunk1 = array.slice(firstElement);
//the remaining numbers
let chunk2 = array.slice(0, firstElement);
//Copy of both chunks now merged and pushed into shifted arrays
shiftedArrays.push([...chunk1, ...chunk2]);
};
return shiftedArrays;
}
function areEqual(shift){
let sortedShift = [...shift].sort((a ,b) => {
return a - b
});
//takes in a single shift and does a deep check to see if the array is equal to sorted version
if(sortedShift.length === shift.length){
return sortedShift.every((element, index) => {
if(element === shift[index]){
return true;
}
return false;
})
}
}
console.log(solution([1,4,2,3]));
console.log(solution([[2, 3, 4, 5, 6, 7, 8, 9, 10, 1]]))
How do I keep the for loop running even after the first false is returned from the areEqual() function?
A side note: I understand that this could probably use some refactoring... like, I was working on this with someone earlier and they mentioned how I can simply shift the array by writing a helper function like shiftArray(arr){return arr.push(arr.pop())} but I don't get how that implementation would work considering that all that's returned is the value that was taken out of the array, not the new shifted array.
You may be doing too much work.
Say you have an array A of n integers, zero indexed.
Parse the array from index 0 to n mod n (so 0 twice). Count the number of pairs where the latter integer is less than the former, and store the first index where this happens.
If the count is 1 and the location is k (so A[k] < A[k-1]), then a cyclic shift of either -k or n-k will convert A to a sorted array. If the count is greater than 1 then there's no solution.
E.g., [4,5,0,1,2,3] -- we see k=2 is the only index which has a value below its predecessor, and a cyclic shift of -2 or 4 forms [0,1,2,3,4,5] which is sorted.
I am trying the "CountDistinctSlices" codility question. I tried my best scored 30% so tried to look up on someone who did it for insights. and basically what I don't get in the answer is the use of the initialized seen array(and M for that matter) and how its being used can someone who get it kindly walk me through this code.
THis is the Answer I found without explanation
function solution(M, A) {
// write your code in JavaScript (Node.js 8.9.4)
let sum = 0;
let front = 0;
let back = 0;
const seen = new Array(M+1).fill(false);
while (front < A.length && back < A.length){
while (front < A.length && seen[A[front]] !== true){
sum += (front-back+1);
seen[A[front]] = true;
front += 1;
}
while (A[back] !== A[front]){
seen[A[back]] = false;
back += 1;
}
seen[A[back]] = false;
back += 1;
}
return Math.min(sum, 1000000000);
}
This is the full question
An integer M and a non-empty array A consisting of N non-negative
integers are given. All integers in array A are less than or equal to
M.
A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice
of array A. The slice consists of the elements A[P], A[P + 1], ...,
A[Q]. A distinct slice is a slice consisting of only unique numbers.
That is, no individual number occurs more than once in the slice.
For example, consider integer M = 6 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 5
A[3] = 5
A[4] = 2
There are exactly nine distinct slices: (0, 0), (0, 1), (0, 2), (1,
1), (1, 2), (2, 2), (3, 3), (3, 4) and (4, 4).
The goal is to calculate the number of distinct slices.
Write a function:
function solution(M, A);
that, given an integer M and a non-empty array A consisting of N
integers, returns the number of distinct slices.
If the number of distinct slices is greater than 1,000,000,000, the
function should return 1,000,000,000.
For example, given integer M = 6 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 5
A[3] = 5
A[4] = 2
the function should return 9, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
M is an integer within the range [0..100,000];
each element of array A is an integer within the range [0..M].
Lets go through the algorithm first:
You first start from the beginning and traverse until you find a duplicate. Now you have a range = [ back - front ]
The code called this range [back, front] where "back" is beginning and "front" is your moving pointer.
How many distinct slices are there in this range? There are slices of size 1, 2, .... front - back + 1, so it is sum = 1 + 2 + 3 + ... [front - back + 1]
Now that you encountered a duplicate what you should do ? To understand lets take the example in the question : [3,4,5,5,2]. Now front reached 5. Now we should bring the back pointer to 5 but also at the same time remove the elements 3, 4, 5 from the set because those may be present after the current front. So back comes to 5 which is currently pointed by front.
Lets take another example [1,2,1] , for this front will reach 1 at the index 2 because that is the first duplicate found. Now where should back come to? It should come to 2 because that will be the position where set won't have any duplicates when you delete the elements in the set while you move the back pointer.
Do this until the front reaches the end of the array.
Your question about seen:
How do you find a duplicate in an array? You could use either a Set or you could use a boolean array. I think the only purpose of M in this question is to specify the maximum value that an element in the array can have. So the code used a boolean array of size M.
If you use the boolean array, once you find an element of value say v you can just say boolean_arr[v] = true that means it was "seen".
Or you could use a set and create a new one when needed without having to clear your whole boolean array everytime you find a duplicate - by letting the JavaScript to handle the garbage collection - something like below ( not fully tested ):
function solution(M, A) {
let sum = 0;
let front = 0;
let back = 0;
let set = new Set();
while (front < A.length) {
while (front < A.length && !set.has(A[front])){
sum += (front-back+1);
set.add(A[front]);
front += 1;
}
while (A[back] != A[front]) {
set.delete(A[back]);
back += 1;
}
set.delete(A[back]);
back += 1;
}
return Math.min(sum, 1000000000);
}
I was wondering how this worked, and what each part meant.
const factors = number => [...Array(number + 1).keys()].filter(i=>number % i === 0);
I have done some research on some of the bits but I don't really understand how it goes together as a whole. Thanks in advance :)
Let's break it down:
Array(number + 1): Creates an array with number + 1 empty elements
Array(number + 1).keys(): Retrieves the indices of the array in the form of an iterator
[...Array(number + 1).keys()]: Creates an array from the iterator (contains elements 0, 1, 2, ..., (number - 1), number)
.filter(cb): Calls the function cb for each value in the array, and returns a new array containing the values for which the callback (cb) has returned true (uses implicit boolean conversion)
i => number % i === 0: Gets called for each value of the array, current element stored to i
number % i: Divides number with i and returns the remainder
number % i === 0: Checks if the remainder equal to zero (i.e. if number perfectly divisible by i)
.filter(i => number % i === 0): Filters the array, keeping the elements that are the divisors of number
So,
number => [...Array(number + 1).keys()].filter(i => number % i === 0);
creates a function, that returns an array with the divisors of the given number.
Let's break it down...
Array(number + 1)
This is the array constructor, creating a sparse array with length number + 1
.keys()
Using Array.prototype.keys() to get an iterator for the array keys which are [0, number]
FYI, this is interval notation, not an array
[...Array(number + 1).keys()]
Using the spread syntax on an iterator converts it to an array, so now we have something like
[0, 1, 2, ..., number]
.filter(i=>number % i === 0)
Uses Array.prototype.filter() to reduce the ranged array above to one where the values divide evenly into number
A low-fi version of this might look something like
function factors(number) {
const factors = []
for (let i = 0; i <= number; i++) {
if (i % number === 0) {
factors.push(i)
}
}
return factors
}
For clarity sake, this is what I mean. I want to look for the two least numbers in an array(sorted) that will generate a particular number. The steps go thus:
Loop through the array and each time set a current value that other
numbers will be deducted from.
Keep doing that till you find the numbers that match the problem and return them.
Example. I need two numbers that when subtracted from the array will give a result of 2.
let givenArray = [1, 4, 8, 10];
The subtraction should go thus: 4 - 1 = 3(doesn't match); //continue
8 - 4 = 1(doesn't match);// continue
8 - 1 = 7(doesn't match); //continue
10 - 8 = 2(match found); //stop and return 8, 10.
NOTE: This same array may contain a 6 and 8 or 8 and 10 that will both yield 2 but 6 and 8 should be returned instead. The way the array is generated isn't of much importance.
P.S: I eventually solved it yesterday but I won't mind other ideas on how to go about it.
This solution takes the advantage of a hash table and uses a single loop approach for getting the two values out of an array to balance two values.
First, take the absolute delta of the two values of arrayA and take this for getting the values out of the greater array.
Then reduce the greater array arrayB by checking if the needed value exist and if the sum is smaller then a previously found set.
The argument for checking is build out of the absolute delta of delta and v, the actual value of the array or by taking the sum of delta and v.
The last point, and to make this all working, the actual value v is included into the hash table, for a later look up.
The result is either an array of two values, which balance the other two values or undefined, if no values are found.
var arrayA = [3, 5],
arrayB = [2, 9, 5, 4],
delta = Math.abs(arrayA[0] - arrayA[1]),
values = {},
result = arrayB.reduce((r, v) => {
function check(w) {
if (!values[w] || r && r[0] + r[1] < v + w) return;
r = [w, v];
}
check(Math.abs(delta - v));
check(delta + v);
values[v] = true;
return r;
}, undefined);
console.log(result);
I'm not sure I understood correctly, but perhaps this is what you need:
let result = arrayA[1] - arrayA[0];
let i, j;
for (i = arrayB.length - 1; i >= 1; i--) { // Set the first value
for (j = arrayB.length - 1; j >= 1; j--) { // Set the second value
if (i !== j) {
if (
arrayB[i] - arrayB[j] === result // Check substraction
|| arrayB[i] + arrayB[j] === result // Check addition
) return [arrayB[i], arrayB[j]];
}
}
}
I am writing a function that takes a number and returns the factorial of it. It works, but why do you have to "-1" on the first parameter of the second for() statement?
var firstFactorial = function(num){
var numBreakdown = [];
var total = 1;
for(var i = 1; i <= num; i++){
numBreakdown.push(i);
}
for(var y = numBreakdown.length-1; y > 0; y--){
total *= numBreakdown[y]
}
console.log(total);
return total;
}
firstFactorial(7);
This is because, in the array, index (position) of the last element is always one less than the length. And you have to start you operation from the last element which is on length-1 index.
This is your array with all the seven elements and their index..
numBreakdown=[1,2,3,4,5,6,7]
| | | | | | |
index:0,1,2,3,4,5,6
You can see to access the element 7 you have to use numBreakdown[6] or numBreakdown[length-1], here length=7 or numBreakdown[y] where y=length-1.
Ryan explained the reasoning behind the -1 well in the comments above:
Array indexes go from 0 to one less than the length. ['first', 'second', 'third'] has indexes 0, 1, and 2. Not sure why you would store the numbers to multiply in an array, though; you can just multiply total in the first place.
As for the factorial function, most of it is unnecessary, including the use of arrays to store the factors of the factorial. See the alternative implementation below.
function factorial (n) {
if (n < 0) throw new TypeError('`n` must be non-negative')
var result = 1
while (n > 1) result *= n--
return result
}
console.log(factorial(0)) //=> 1
console.log(factorial(1)) //=> 1
console.log(factorial(7)) //=> 5040
If you would like any further clarification or have questions about the above code, feel free to ask!