// Get # of digits in a number.
function numDigits(num) {
if (num === 0) return 1;
return Math.floor(Math.log10(Math.abs(num))) + 1;
}
// Get nth digit from right in a number.
function getNth(num, n) {
return Math.floor((num / Math.pow(10, n - 1)) % 10);
}
// Gauss Triangular Number - Like factorial but with addition instead of multiplication.
// triangle(5) => 15 (5 + 4 + 3 + 2 + 1)
function triangle(num) {
return (num ** 2 + num) / 2;
}
// Least Common Multiple - The smallest number which can be divided by two given numbers.
function lcm(a, b) {
return a * b / gcd(a, b);
}
// Greatest Common Divisor - The biggest number which can divide evenly into both the given numbers.
function gcd(a, b) {
while (a % b > 0)
[b, a] = [a % b, b];
return b;
}
// Function - Returns count of numbers divisible by a, b, or c under a given n number.
// n(AuBuC) = n(A) + n(B) + n(C) - n(A∩B) - n(A∩C) - n(B∩C) + n(A∩B∩C)
function unionCountDivisible(n, a, b, c) {
const ab = lcm(a, b), bc = lcm(b, c), ac = lcm(a, c), abc = lcm(ab, c);
return Math.floor(n / a) + Math.floor(n / b) + Math.floor(n / c) - Math.floor(n / ab) - Math.floor(n / bc) - Math.floor(n / ac) + (Math.floor(n / abc));
}
// Use Dynamic Programming (DP, Memoization, Tabulation) when
// 1. There are overlapping subproblems
// 2. An optimal substructure