Having the following input string: 923857614
This is represented into a matrix like this:
9 2 3
8 5 7
6 1 4
Having a moving sequence like this: 423692, this means that we start in point 4, we move to 2, then to 3, then to 6, then to 9 and finally to 2.
It must be computed the length of the road. At beginning it starts from 0, if the next step is adjacent to the current one, add 1, if it isn't adjacent, add 2.
How I tried to do it:
function computeRoadLength(keypad, movingSequence) {
// build the matrix
const arr = [[keypad[0], keypad[1], keypad[2]],
[keypad[3], keypad[4], keypad[5]],
[keypad[6], keypad[7], keypad[8]]];
let roadLength = 0;
for (i = 0; i < movingSequence.length; i++) {
// some way to compute the distance here
if (arr[i] > arr[i+1]) roadLength = roadLength + 1;
if (arr[i] < arr[i+1]) roadLength = roadLength + 2;
}
return roadLength;
}
computeRoadLength(923857614, 423692); // 2 + 1 + 2 + 2 + 1 = 8, should return 8
You could take a different approach by using an object of positions of all keypad values and take the absolute delta of the positions.
For adding to movingSequence add one or max two.
function computeRoadLength(keypad, movingSequence) {
const positions = {};
for (let i = 0; i < keypad.length; i++) {
positions[keypad[i]] = [Math.floor(i / 3), i % 3];
}
let roadLength = 0,
last = positions[movingSequence[0]];
for (let i = 1; i < movingSequence.length; i++) {
const
item = positions[movingSequence[i]],
sum = Math.abs(last[0] - item[0]) + Math.abs(last[1] - item[1]);
roadLength += Math.min(sum, 2);
last = item;
}
return roadLength;
}
console.log(computeRoadLength('923857614', '423692')); // 2 + 1 + 2 + 2 + 1 = 8
Related
I'm given a number and I need to find the sum of the multiples of 3 and 5 below the number.
For example:
20 => 78 = 3 + 5 + 6 + 9 + 10 + 12 + 15 + 18
My code works, but not for numbers greater than 1,000,000 (I tested it for 100,000 - it gives the result with 2sec delay). So, it should be optimized. Could someone help me? Why is my code slow? Thanks.
My logic is as follows:
add multiples to an array
filter duplicate values
sum all values
my code:
function sumOfMultiples(number) {
let numberBelow = number - 1;
let numberOfThrees = Math.floor(numberBelow / 3);
let numberOfFives = Math.floor(numberBelow / 5);
let multiples = [];
let multipleOfThree = 0;
let multipleOfFive = 0;
for (var i = 0; i < numberOfThrees; i++) {
multiples.push(multipleOfThree += 3);
}
for (var j = 0; j < numberOfFives; j++) {
multiples.push(multipleOfFive += 5);
}
return multiples
.filter((item, index) => multiples.indexOf(item) === index)
.reduce((a, b) => a + b);
}
You can also do this without using any loops.
For example if N is 1000, the sum of all multiples of 3 under 1000 is 3 + 6 + 9 ..... 999 => 3( 1 + 2 + 3 .... 333)
Similarly for 5, sum is 5(1 + 2 + 3 .... 200). But we have to subtract common multiples like 15, 30, 45 (multiples of 15)
And sum of first N natural numbers is N*(N+1)/2;
Putting all of this together
// Returns sum of first N natural numbers
const sumN = N => N*(N+1)/2;
// Returns number of multiples of a below N
const noOfMulitples = (N, a) => Math.floor((N-1)/a);
function sumOfMulitples(N) {
const n3 = noOfMulitples(N, 3); // Number of multiples of 3 under N
const n5 = noOfMulitples(N, 5); // Number of multiples of 5 under N
const n15 = noOfMulitples(N, 15); // Number of multiples of 3 & 5 under N
return 3*sumN(n3) + 5*sumN(n5) - 15*sumN(n15);
}
You can just run a loop from 1 to number, and use the modulo operator % to check if i divides 3 or 5:
function sumOfMultiples(number) {
var result = 0;
for (var i = 0; i < number; i++) {
if (i % 5 == 0 || i % 3 == 0) {
result += i;
}
}
return result;
}
console.log(sumOfMultiples(1000));
console.log(sumOfMultiples(100000));
console.log(sumOfMultiples(10000000));
You can do that just using a single loop.
function sumOfMultiples(number) {
let sum = 0;
for(let i = 1; i < number; i++){
if(i % 3 === 0 || i % 5 === 0){
sum += i;
}
}
return sum;
}
console.time('t');
console.log(sumOfMultiples(100000))
console.timeEnd('t')
You can do something like this
Set the difference equal to 5 - 3
Start loop with current as 0, keep looping until current is less than number,
Add 3 to current in every iteration,
Add difference to current and check if it is divisible by 5 only and less than number, than add it final result,
Add current to final result
function sumOfMultiples(number) {
let num = 0;
let difference = 5 - 3
let current = 0
while(current < number){
current += 3
let temp = current + difference
if((temp % 5 === 0) && (temp %3 !== 0) && temp < number ){
num += temp
}
difference += 2
if(current < number){
num += current
}
}
return num
}
console.log(sumOfMultiples(20))
console.log(sumOfMultiples(1000));
console.log(sumOfMultiples(100000));
console.log(sumOfMultiples(10000000));
you can do something like this
function multiplesOfFiveAndThree(){
let sum = 0;
for(let i = 1; i < 1000; i++) {
if (i % 3 === 0 || i % 5 === 0) sum += i;
}
return sum;
}
console.log(multiplesOfFiveAndThree());
I am using an array in order to calculate large powers of 2. The arrays add to each other and afterwords they calculate the carries and loop n-1 amount of times until i end up with the number as an array. I do this in order to avoid the 15 digit limit that JavaScript has.
Everything works fine once i reach n = 42, where the carries start to be overlooked and numbers aren't reduced, producing wrong answers.
I tried changing the method of which the carry is processed inside the while loop from basic addition to integer division and modulus
Sounds stupid but i added an extra loop to check if any elements are greater than 10 but it didn't find them.
for (var n = 1; n <= 100; n++) {
for (var i = 0, x = [2]; i < n - 1; i++) { // Loop for amount of times to multiply
x.unshift(0)
for (var j = x.length - 1; j > 0; j--) { // Double each element of the array
x[j] += x[j]
}
for (j = x.length - 1; x[j] > 0; j--) { // Check if element >= 10 and carry
while (x[j] >= 10) {
x[j - 1] += Math.floor(x[j] / 10)
x[j] = x[j] % 10
}
}
if (x[0] === 0) {
x.shift()
}
}
console.log('N: ' + n + ' Array: ' + x)
}
The expected results are that each element in the array will be reduced into a single number and will "carry" onto the element to its left like :
N: 1 Array: 2
N: 2 Array: 4
N: 3 Array: 8
N: 4 Array: 1,6
N: 5 Array: 3,2
N: 6 Array: 6,4
but starting at n=42 carries get bugged looking like this:
N: 42 Array: 4,2,18,18,0,4,6,5,1,1,1,0,4
N: 43 Array: 8,4,36,36,0,8,12,10,2,2,2,0,8
N: 44 Array: 1,7,5,9,2,1,8,6,0,4,4,4,1,6
N: 45 Array: 2,14,10,18,4,2,16,12,0,8,8,8,3,2
N: 46 Array: 7,0,3,6,8,7,4,4,1,7,7,6,6,4
N: 47 Array: 14,0,7,3,7,4,8,8,3,5,5,3,2,8
What's the error that could be throwing it off like this?
I think the reason your code doesn't work is this line for (j = x.length - 1; x[j] > 0; j--) { // Check if element >= 10 and carry you don't want to check for x[j] > 0 but j > 0.
Also your second loop: for (var i = 0, x = [2]; i < n - 1; i++) { - you don't need it, there is no reason to recalculate everything on every iteration, you can use previous result.
You can also double values this way : x = x.map(n => n * 2) (seems a bit more coventional to me).
And there is no need to x[j - 1] += Math.floor(x[j] / 10) it could be just x[j - 1] += 1 as previous numbers are up to 9, doubled they are no more than 18 so 1 is the only case if x[j] >= 10.
Could be the code:
let x = [2] // starting point
for (var n = 1; n <= 100; n++) {
x = [0, ...x].map(n => n * 2)
for (j = x.length - 1; j > 0; j--) {
if (x[j] >= 10) {
x[j - 1] += 1
x[j] %= 10
}
}
if (x[0] === 0) {
x = x.slice(1)
}
console.log('N: ' + n + ' Array: ' + x)
}
If all you want are large powers of 2, why are you going through the insane hassle of using lists to calculate that? Isn't this the exact same:
function BigPow2(x, acc=2.0) {
//document.writeln(acc);
acc = acc >= 5 ? acc / 5 : acc * 2;
return x <= 1 ? acc : BigPow2(x-1, acc);
}
Or alternatively, use BigInt?
For my purpose I need to create loop where one variable is looping in this way:
0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1...
It's look simple but more than hour I wonder how to do it.
My purpose is moving the star in this way
*....
.*...
..*..
...*.
....*
...*.
..*..
.*...
*....
*....
.*...
..*..
...*.
....*
Write that loop as a generator (function *... yield) and then consume it when you need it (for...of). Of course, the consuming code must provide some termination condition.
function* bounce(min, max) {
while (1) {
for (let i = min; i < max; i++)
yield i;
for (let i = max; i > min; i--)
yield i;
}
}
STEPS = 10
for(let x of bounce(0, 4)) {
console.log(x)
if (--STEPS === 0) break;
}
You can use the following code to generate the number pattern that you require. However, you wont be able to run it infinitely since it will crash the browser.
If you want to test, I have added instructions for making the loop infinite.
For you requirement, a larger value for rep variable will be enough.
let min = 0; // Start/min value
let max = 4; // Max value
let dir = 1; // Count direction (+1/-1)
let counter = min; // Your counter variable
let rep = 24; // Remove this line and change condition inside while to true for infinite loop
do {
console.log(counter);
dir = counter===max?-1:counter===min?1:dir;
counter+=dir;
} while (rep-->0); // Change this expression to true for infinite loop
You can use setTimeout or setInterval for doing that:
let number = 0;
let increment = 1;
const from = 0;
const to = 4;
const starDiv = document.getElementById("star");
function printStar(number) {
const text = [0, 1, 2, 3, 4].map(
i => (i === number) ? '*' : '-'
).join('');
starDiv.innerText = text;
}
function loop() {
printStar(number);
number += increment;
if (number == to) {
increment = -1;
} else if (number == from) {
increment = 1;
}
}
const time = 10; // 10 millisecond between step
setInterval(loop, time);
<div id="star">
</div>
You could have a simple counter and then use modulo 8 to get iterations.
let x = (i += direction) % 8;
let y = x > 4 ? 8 - x : x;
This example even prints the ascii art ;)
let i = -1;
let direction = +1;
const out = [
"*....",
".*...",
"..*..",
"...*.",
"....*",
"...*.",
"..*..",
".*...",
"*....",
];
setInterval(function() {
let x = (i += direction) % 8;
let y = x > 4 ? 8 - x : x;
window.document.write(y + " " + out[x] + "<br>");
}, 1000);
(function(min,max,max_loops)
{
for(var loop = 1; loop <= max_loops; loop++, [min,max] = [-max,-min])
{
for(num = min; num < max + (loop == max_loops); num++)
{
console.log(".".repeat(Math.abs(num)) + "*" + ".".repeat(Math.max(Math.abs(max),Math.abs(min)) - Math.abs(num)))
}
}
})(0,4,3)
But since you need an infinite loop, using generator should be more suitable.
This question already has answers here:
Finding minimal absolute sum of a subarray
(11 answers)
Closed 4 years ago.
Hi I've taken Codility test twice and scored 0. Please help me in solving the issue using JavaScript.
A non-empty array A consisting of N integers is given. A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice of array A. The sum of a slice (P, Q) is the total of A[P] + A[P+1] + ... + A[Q].
A min abs slice is whose absolute sum is minimal.
For example, array A such that:
A[0] = 2
A[1] = -4
A[2] = 6
A[3] = -3
A[4] = 9
contains the following slice among others:
(0,1), whose absolute sum is = |2 + (-4)| = 2
(0,2), whose absolute sum is = |2 + (-4) + 6| = 4
(0,3), whose absolute sum is = |2 + (-4) + 6 + (-3)| = 1
(1,3), whose absolute sum is = |(-4) + 6 + (-3)| = 1
(1,4), whose absolute sum is = |(-4) + 6 + (-3) + 9| = 8
(4,4), whose absolute sum is = |9| = 9
Both slices (0,3) and (1,3) are min abs slice and their absolute sum equals 1.
Write a function:
function solution(A);
that, given a non-empty array A consisting of N integers, return the absolute sum of min abs slice.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..1,000,000];
each element of array A is an integer within the range [−10,000..10,000];
Here is my solution:
function solution(A, i = 0, sum = 0) {
const N = A.length;
if (N === 0) {
return 0;
}
if (N == 1) {
return Math.abs(A[0]);
}
A.sort();
// All positives
if (A[0] >= 0 && A[N - 1] >= 0) {
return Math.abs(A[0]);
}
// All Negatives
if (A[0] <= 0 && A[N - 1] <= 0) {
return Math.abs(A[N - 1]);
}
let currAbsSum = 0;
let minAbsSum = Number.MAX_SAFE_INTEGER;
for (var i = 0; i < N; i++) {
let j = N - 1;
while (j >= i) {
currAbsSum = Math.abs(A[i] + A[j]);
if (currAbsSum === 0) {
return 0;
}
minAbsSum = Math.min(currAbsSum, minAbsSum);
if (Math.abs(A[i]) > Math.abs(A[j])) {
i++;
} else {
j--;
}
}
if (A[i] > 0) break;
}
return minAbsSum;
}
Here is a javascript version of O(n log n) answer taken from here:
function solution(A) {
if (1 == A.length) return Math.abs(A[0]);
let sums = new Array(A.length + 1);
let minAbsSum = Number.MAX_SAFE_INTEGER;
sums[0] = 0;
for (var i = 0; i < A.length; i++) {
sums[i + 1] = A[i] + sums[i];
}
sums.sort();
for (var i = 1; i < sums.length; i++) {
minAbsSum = Math.min(minAbsSum, Math.abs(sums[i] - sums[i - 1]));
}
return minAbsSum;
}
console.log(solution([2, -4, 6, -3, 9]))
console.log(solution([10, 10, 10, 10, 10, -50]))
I have a problem with the following task. I want to achieve this output for n = 5:
* 2 3 4 5
* * 3 4 5
* * * 4 5
* * * * 5
* * * * *
* * * * *
* * * * 5
* * * 4 5
* * 3 4 5
* 2 3 4 5
I'm stuck in the second part of the exercise. My code for now:
var n = 5;
var numbers = '';
for (var i = 1; i <= n; i++) {
numbers += i;
}
for (var i = 0; i < n; i++) {
numbers = numbers.replace(numbers[i], '*');
console.log(numbers);
}
So far I have this result:
*2345
**345
***45
****5
*****
So now I need to add the spaces between numbers/stars, and make a reverse loop. I have no idea how to do it.
In addition, there is probably a faster solution to this task than I did.
You can save each of the numbers you generate on a stack (an array), and then pop them from the stack in reverse order:
var n = 5;
var numbers = '';
var stack = []; // <--- add this
for (var i = 1; i <= n; i++) {
numbers += i + ' '; // add a space here
}
for (var i = 0; i < n; i++) {
numbers = numbers.replace(i, '*'); // find/replace the digit
console.log(numbers);
stack.push(numbers); // <--- push on stack
}
while (stack.length > 0) {
numbers = stack.pop(); // <--- pull in reverse order
console.log(numbers); // <--- and print
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
A similar way, without the use of a stack, delays the output, and gathers all the strings in two longer strings which each will have multiple lines of output:
var n = 5;
var numbers = '';
var stack = [];
var output1 = ''; // <-- add this
var output2 = ''; //
for (var i = 1; i <= n; i++) {
numbers += i + ' ';
}
numbers += '\n'; // <-- add a newline character
for (var i = 0; i < n; i++) {
numbers = numbers.replace(i, '*');
output1 += numbers;
output2 = numbers + output2; // <-- add reversed
}
console.log(output1 + output2); // <-- output both
.as-console-wrapper { max-height: 100% !important; top: 0; }
Sticking with something similar to your approach:
var n = 5;
var numbers = '';
for (var i = 1; i <= n; i++) {
numbers += i + ' ';
}
for (var i = 0; i < n; i++) {
numbers = numbers.substr (0, i * 2) + '*' + numbers.substr (i * 2 + 1);
console.log(numbers);
};
for (var i = n - 1; i >= 0; i--) {
console.log(numbers);
numbers = numbers.substr (0, i * 2) + (i + 1) + numbers.substr (i * 2 + 1);
};
The disadvantage of this approach is that it only works for 0-9 because the string positions break when the numbers aren't single digits.
The way I might approach the problem is by having a variable that keeps track of up to which number needs to be an asterisk, doing the first half, then using a whole new for loop to do the second half.
For instance,
String result = '';
String line = '';
int counter = 1;
for (int line = 1; line =< 5; line++) {
for (int i = 1; i =< 5; i++) { // note that we start at 1, since the numbers do
if (i <= counter) {
line += '*'; // use asterisk for positions less than or equal to counter
else {
line += i; // otherwise use the number itself
}
line += ' '; // a space always needs to be added
}
result += line + '\n'; // add the newline character after each line
counter++; // move the counter over after each line
}
Then you can do the same loop, but make the counter go backwards. To do that, set counter to 5 before you begin the loop (since Strings are zero-indexed) and do counter-- after each line.
Alternatively if you don't want to write two loops, you can increase the outer for loop's limit to 10 and have an if statement check if you should be subtracting from counter instead of adding, based on the value of line
Decided to use this as an excuse to get more practice with immutable mapping and reducing. I used an array to hold all the rows, and reduce them at the end to a string. Each row starts as an array holding 1 to n, and each column number is then mapped to an asterisk based on the case:
if rowIndex <= number:
rowIndex.
else:
rowIndex - (2 * (rowIndex - number) - 1)
Essentially, [n + 1, n * 2] maps to (1, 3, 5, ..., n - 3, n - 1), which subtracted from the original range becomes [n, 1]. For the row, check if the currently selected column is less than or equal to its row's translated index, and return an asterisk or the number.
// expansion number (n by 2n)
const maxNum = 5;
// make an array to size to hold all the rows
const result = Array(maxNum * 2)
// Fill each row with an array of maxNum elements
.fill(Array(maxNum).fill())
// iterate over each row
.map((row, rowIndex) =>
// iterate over each column
row.map((v, column) => (
// check if the column is less than the translated rowIndex number (as mentioned above)
column < ((rowIndex <= maxNum) ?
rowIndex + 1 :
2 * maxNum - rowIndex
// if it is, replace it with an asterisk
)) ? "*" : column + 1)
// combine the row into a string with each column separated by a space
.reduce((rowAsString, col) => rowAsString + " " + col)
// combine all rows so they're on new lines
).reduce((rowAccum, row) => rowAccum + "\n" + row);
console.log(result);