Google Code Jam 2016 : How Can I optimize the Code? - javascript

Problem:
Bleatrix Trotter the sheep has devised a strategy that helps her fall asleep faster. First, she picks a number N. Then she starts
naming N, 2 × N, 3 × N, and so on. Whenever she names a number, she
thinks about all of the digits in that number. She keeps track of
which digits (0, 1, 2, 3, 4, 5, 6, 7, 8, and 9) she has seen at least
once so far as part of any number she has named. Once she has seen
each of the ten digits at least once, she will fall asleep.
Bleatrix must start with N and must always name (i + 1) × N directly after i × N. For example, suppose that Bleatrix picks N =
1692. She would count as follows:
N = 1692. Now she has seen the digits 1, 2, 6, and 9.
2N = 3384. Now she has seen the digits 1, 2, 3, 4, 6, 8, and 9.
3N = 5076. Now she has seen all ten digits, and falls asleep.
What is the last number that she will name before falling asleep? If she will count forever, print INSOMNIA instead.
https://code.google.com/codejam/contest/6254486/dashboard
Array.prototype.unique = function () {
return this.filter(function (value, index, self) {
return self.indexOf(value) === index;
});
}
var uniqueArr = [];
var Number = 1692;//Any number
for (i = 1; ; i++) {
var x = Number * i;
while (x > 0) {
uniqueArr.push(x % 10); //Converting number to Digits and pushing them into an array.
x = Math.floor(x / 10);
}
var ar = uniqueArr.unique();
if (ar.length == 10) {
console.log(uniqueArr.unique(), Number * i);
break;
}
}

As long as x is always a positive number* (which is the case here) you could use
x = ~~(x / 10)
instead of
x = Math.floor(x / 10)
Which does the same job but is ~5 times faster. Its more an obvious improvement but it optimize the code anyway.
* ~~ is a bitwise operator, which just cuts off everything after the comma. So ~~-6.6 will result -6, but Math.floor(-6.6) gives you a -7. Be carefull here.

Related

Alternate numbers into two rows

I think I'm having a brain fart, because I can't figure out a simple formula to be able sort a sequence of number into specific order so it can be printed 2 numbers per sheet of paper (one number on one half and second number on second half), so when the printed stack of paper cut in half, separating the numbers, and then these halves put together, the numbers would be in sequence.
So, let's say I have 5 numbers: 3,4,5,6,7, the expected result would be 3,6,4,7,5 or
0,1,2,3,4,5,6,7 would become 0,4,1,5,2,6,3,7
My thought process is:
create a loop from 0 to total number of numbers
if current step is even, then add to it total numbers divided in 2
Obviously, I'm missing a step or two here, or there is a simple mathematical formula for this and hopefully someone could nudge me in a right direction.
This is what I have so far, it doesn't work properly if start number set to 1 or 3
function show()
{
console.clear();
for(let i = 0, count = end.value - start.value, half = Math.round(count/2); i <= count; i++)
{
let result = Math.round((+start.value + i) / 2);
if (i && i % 2)
result = result + half -1;
console.log(i, "result:", result);
}
}
//ignore below
for(let i = 0; i < 16; i++)
{
const o = document.createElement("option");
o.value = i;
o.label = i;
start.add(o);
end.add(o.cloneNode(true));
}
start.value = 0;
end.value = 7;
function change(el)
{
if (+start.value > +end.value)
{
if (el === start)
end.value = start.value;
else
start.value = end.value;
}
}
<select id="start" oninput="change(this)"></select> -
<select id="end" oninput="change(this)"></select>
<button onclick="show()">print</button>
P.S. Sorry, about the title, couldn't come up with anything better to summarize this.
You could get the value form the index
if odd by using the length and index shifted by one to rigth (like division by two and get the integer value), or
if even by the index divided by two.
function order(array) {
return array.map((_, i, a) => a[(i % 2 * a.length + i) >> 1]);
}
console.log(...order([3, 4, 5, 6, 7]));
console.log(...order([0, 1, 2, 3, 4, 5, 6, 7]));

Count how many palindrome numbers are on the segment [1, 10 ** n] (n <100)

It is necessary to calculate how many palindrome numbers are on the segment [1, 10 ** n] (n <100).
function f(n) {
let res = 10 ** (parseInt(n / 2) + n % 2);
return res - res / 10;
}
function countPalindromes(n) {
let count = 0;
for (let i = 1; i <= n; i++) {
count += f(i);
}
return count;
}
for (let i = 1; i < 100; i++) {
console.log(i, f(i), countPalindromes(i));
}
Problems:
Over time js returns the result in exponential form, and the result cannot be translated into a string.
Adding such large numbers into a column does not work
And so, how can I count the number of palindromes in the segment [1, 10 ** n] (n <100)???
Let's start with a smaller problem first. How many n digit palindromic numbers exist?
If n is even, let the number be of the form _ _ _ _ (midpoint) _ _ _ _. Now, in the first digit, you can't fill 0, so you have 9 options (1-9). For the second digit to the n/2th digit, you can fill any of the digits in 0-9. Since we're dealing with palindromes, second half of the number will have the same digits as the first half. So, using basic counting, total number of n digit palindromes when n is even is 9*[10*10*...10 (n/2)-1 times] = 9 * 10^((n/2)-1)
When n is odd, the analysis will be similar, but with two differences:
You have 10 choices (0-9) for the midpoint.
There are (n-1)/2 digits on either side of the midpoint, where the first digit can't be 0.
Again, using basic counting, number of palindromes if n is odd = 9 (for first digit) * 10 (for midpoint) * 10^((n/2)-2) (the remaining digits) = 9 * (10^(n/2)-1), similar to the even case.
Thus, number of n digit palindromes = 9 * (10^(n/2)-1) if n is greater than 1. After that, you just have to loop n from 2 to 100 to get the total count of palindromic numbers you need.
I'm not 100% sure, so correct me if I'm wrong. It works, check the code at the bottom.
There should be two kinds of palindromes: ones with odd number of digits and ones with even number of digits. You can go from one palindrome to another (of the same kind) by appending and prepending the same digit to the first one. So...
Single-digit palindromes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
For every single-digit palindrome, we can construct 10 3-digit palindromes:
000, 101, 202, ..., 010, 111, 212, ..., 898, 999.
Similarly, for every 3-digit palindromes, we can construct 10 5-digit palindromes.
10 ** n would have up to n-digit palindromes. Let's count:
10 ** 1 single-digit, 10 ** 2 3-digit, 10 ** 3 5-digit, ..., 10 ** ((n + 1) / 2) n-digit.
The same can be done for double-digit palindromes (00, 11, 22, 33, 44, 55, 66, 77, 88, 99), to iteratively obtain palindromes with an even number of digits.
Then we need to drop the 'illegal' numbers - numbers starting with the digit 0.
It works. Yay!
// Counting without creating the numbers
function getSmartCount(n) {
let smartPalindromeCount = 0;
let startingWithZeroCount = 0;
for (let digits = 1; digits <= n; digits += 2) { // even digits
const power = (digits + 1) / 2;
smartPalindromeCount += 10 ** power;
startingWithZeroCount += 10 ** (power - 1); // the zero-x-zero numbers
}
for (let digits = 2; digits <= n; digits += 2) { // odd digits
const power = digits / 2;
smartPalindromeCount += 10 ** power;
startingWithZeroCount += 10 ** (power - 1); // the zero-x-zero numbers;
}
return smartPalindromeCount - startingWithZeroCount;
}
// Counting by creating the numbers
function getCountIteratively(n) {
const singleDigitPalindromes = '0123456789'.split('');
const doubleDigitPalindromes = singleDigitPalindromes.map(x => x + x);
const palindromes = [...singleDigitPalindromes, ...doubleDigitPalindromes];
const nestedPalindromes = [
singleDigitPalindromes,
doubleDigitPalindromes,
];
for (let digits = 3; digits <= n; digits++) {
const index = digits - 1;
const extraPalindromes = [];
const previousPalindromes = nestedPalindromes[index - 2];
for (const previousPalindrome of previousPalindromes) {
for (const character of singleDigitPalindromes) {
const newPalindrome = character + previousPalindrome + character;
extraPalindromes.push(newPalindrome);
palindromes.push(newPalindrome);
}
}
nestedPalindromes.push(extraPalindromes);
}
const legalPalindromes = palindromes.filter(palindrome => palindrome[0] !== '0');
// console.log(legalPalindromes); // uncomment to see the numbers
return legalPalindromes.length;
}
// Counting by checking every single number
function getCountByBruteForce(n) {
const bruteForcePalindromes = [];
for (let i = 1; i < 10 ** n; i++) {
const leftToRight = i.toString();
const rightToLeft = leftToRight.split('').reverse().join('');
if (leftToRight === rightToLeft) {
bruteForcePalindromes.push(i);
}
}
// console.log(bruteForcePalindromes); // uncomment to see the numbers
return bruteForcePalindromes.length;
}
for (let n = 2; n <= 5; n++) {
console.log({
n,
smart: getSmartCount(n),
byCreatingTheNumbers: getCountIteratively(n),
bruteForce: getCountByBruteForce(n),
});
}

Finding Gapful number in javascript

A number is gapful if it is at least 3 digits long and is divisible by the number formed by stringing the first and last numbers together.
The smallest number that fits this description is 100. First digit is
1, last digit is 0, forming 10, which is a factor of 100. Therefore,
100 is gapful.
Create a function that takes a number n and returns the closest gapful
number (including itself). If there are 2 gapful numbers that are
equidistant to n, return the lower one.
Examples gapful(25) ➞ 100
gapful(100) ➞ 100
gapful(103) ➞ 105
so to solve this i wrote the code that loops from the given number to greater than that and find out if it is or not by
function getFrequency(array){
var i=array
while(i>=array){
let a=i.toString().split('')
let b=a[0]+a[a.length-1]
b= +b
if(i%b==0) return i
i++
}
}
console.log(getFrequency(103))
Thats fine but what if the gapful number is less than the number passed in the function ?
like if i pass 4780 the answer is 4773 so in my logic how do i check simultaneoulsy smaller and greater than the number passed ?
I am only looping for the numbers greater than the number provided in function
You can alternate between subtracting and adding. Start at 0, then check -1, then check +1, then check -2, then check +2, etc:
const gapful = (input) => {
let diff = 0; // difference from input; starts at 0, 1, 1, 2, 2, ...
let mult = 1; // always 1 or -1
while (true) {
const thisNum = input + (diff * mult);
const thisStr = String(thisNum);
const possibleFactor = thisStr[0] + thisStr[thisStr.length - 1];
if (thisNum % possibleFactor === 0) {
return thisNum;
}
mult *= -1;
if (mult === 1) {
diff++;
}
}
};
console.log(
gapful(100),
gapful(101),
gapful(102),
gapful(103),
gapful(104),
gapful(105),
gapful(4780),
);
You could take separate functions, one for a check if a number is a gapful number and another to get left and right values and for selecting the closest number.
function isGapful(n) {
if (n < 100) return false;
var temp = Array.from(n.toString());
return n % (temp[0] + temp[temp.length - 1]) === 0;
}
function getClosestGapful(n) {
var left = n,
right = n;
while (!isGapful(right)) right++;
if (n < 100) return right;
while (!isGapful(left)) left--;
return n - left <= right - n
? left
: right;
}
console.log(getClosestGapful(25)); // 100
console.log(getClosestGapful(100)); // 100
console.log(getClosestGapful(103)); // 105
console.log(getClosestGapful(4780)); // 4773

Having trouble with the Fibonacci Sequence

So I recently discovered this site (https://projecteuler.net). The second problem asks you to find the sum of all even Fibonacci numbers less than four million. I tried to use my limited JavaScript to solve this for me, but it doesn't seem to be working at all. Here is the jsfiddle: http://jsfiddle.net/ophunt/pnf24j7q/3/
Here is the javascript contained therein:
//variables here
var sum = 0;
var fibA = 1;
var fibB = 1;
var store = 0;
//main loop
while (fibA < 4000000) {
store = fibA;
fibA += fibB;
fibB = store;
if (fibA % 2 === 0) {
sum += fibA;
}
}
Document.getElementById("result").innerHTML = sum;
So a few things can help you out here:
The sum up to fibonacci(n) = fibonacci(n+2) - 1
This is nice since you don't have to manually do the sums since you are already doing the sums when you create the sequence
Even fibonacci numbers are every third fibonacci number. This ends up meaning that the sum of the evens is equal to the sum of all divided by two.
For example:
fibs: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
sums: 1, 2, 4, 7, 12, 20, 33, 54, 88
even_sum: 0, 0, 2, 2, 2, 10, 10, 10, 44
Also give a number you can find the which fiboncacci is closest with exceeding it based on some (semi)simple math. (You can also calculate the fibonacci numbers themselves this way, but I'll leave the original function because recursive functions are cool.
The javascript implimentation looks like this:
var findFibNum = function(num) {
var est = Math.log(num * Math.sqrt(5)) /(Math.log((Math.sqrt(5)+1)/2))
return Math.floor(est)
}
Knowing these three things you can make a pretty quick solution:
var top = 4000000;
/* function finds nth fibonacci number */
var fib = function(n){
if (n <=1) return n;
return fib(n-1) + fib(n-2);
}
/* given a number this finds closest n below it i.e. for 34 it give 9
because 34 is the nineth fibonacci number
*/
var findFibNum = function(num) {
var est = Math.log(num * Math.sqrt(5)) /(Math.log((Math.sqrt(5)+1)/2))
return Math.floor(est)
}
var n = findFibNum(top) /* fib(n) is the largest fibonacci below top */
/* the sum of fibonacci number n is fib(n)+2 -1 -- this beats looping and adding*/
var fibsum = fib(n+2) -1
/* it s a nice feature of the sequence that the sum of evens is equal to the sum off all dived by 2 */
var evensum = fibsum/2
Fiddle gives 4613732

Why isn't my attempted solution working?

When I run the code in the console, the browser just stops working (am assuming stack overflow).
I've come up with several different algorithms for solving this problem, but I thought this one would not cause any SOs.
The problem:
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1 3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
Failing solution:
function divisors(n){
var counter = 0;
var triangle = 3;
var triangle_add = 2;
while (counter < n){
for (var i = 1; i = triangle; i++){
if (triangle % i === 0){
counter++;
}
};
if (counter < n){
triangle_add++;
triangle = triangle + triangle_add;
counter = 0;
};
};
return triangle;
};
console.log(divisors(501));
Your solution is not working because, most probably, it is very slow. This problem can be solved much faster by the following method:
Find all the prime numbers smaller than some N (put, for example, N=100'000) using Sieve of Eratosthenes. It is quite fast.
As we know from elementary math each number can be written in the form X=p1^i1*p2^i2*...*pn^in where pj is prime number and ij is the power of corresponding prime number. The number of divisors of X is equal to (i1+1)*(i2+1)*...*(in+1) since that many different ways we can form a number which will be divisor of X. Having an array of prime numbers the number of divisors for X can be calculated quite fast (the code still has place to be optimized):
int divisorCount(long long X)
{
int c = 1;
for (int i = 0; PRIMES[i] <= X; ++i)
{
int pr = PRIMES[i];
if (X % pr == 0)
{
int p = 1;
long long r = X;
while (r % pr == 0)
{
r = r / pr;
++p;
}
c *= p;
}
}
return c;
}
Iterate through all triangle numbers and count divisor numbers for them using the above function. The i-th triangle number is i * (i + 1) / 2, so no need to keep a variable, increment it and add it each time.

Categories