count 9's from 1 to n - 5kyu Kata - javascript

I am working on this kata https://www.codewars.com/kata/count-9-s-from-1-to-n/train/javascript
and i have written this code for it, but its not working. This question is similar to this one Count the number of occurrences of 0's in integers from 1 to N
but it is different because searching for 9's is practically very different to searching for 0's.
think part of the problem with this code is that it takes too long to run...
any advice appreciated!
function has9(n) {
var nine = [];
var ninearr = n.toString().split('');
for (var j = 0; j < ninearr.length; j++) {
if (ninearr[j] == '9') {
nine.push(ninearr[j]);
}
}
return nine.length;
}
function number9(n) {
var arr = [];
var arrnew = [];
for (var i = 0; i <= n; i++) {
arr.push(i);
}
for (var l = 0; l < arr.length; l++) {
arrnew.push(has9(l));
}
var sum = arrnew.reduce((a, b) => a + b, 0);
return sum;
}

Why not a regex based solution? (Too slow as well?)
const count9s = num => num.toString().match(/9/g).length
console.log(count9s(19716541879)) // 2
console.log(count9s(919191919191919)) // 8
console.log(count9s(999)) // 3
console.log(count9s(999999)) // 6

I have taken the above hint and completely re written the code, which I now feel should work, and it does for most inputs, but codewars is saying it fails on some of them. any ideas why?
function nines(n){
if(n>=100){
var q= Math.floor(n/100);
var nq= q * 20;
var r = (n%100);
var s = Math.floor(r/9);
if (r<=90){
return s + nq;
}
if (r == 99){
return 20 + nq;
}
if (90 < r < 100 && r!= 99){
var t = (r-90);
return nq + s + t;
}
}
if (n<100){
if (n<=90){
var a = Math.floor(n/9);
return a ;
}
if (n == 99){
return 20
}
if (90 < n < 100 && n!= 99){
var c = (n-90);
return 10 + c;
}
}
}

=== UPDATE ===
I just solved your kata using
function number9Helper(num) {
var pow = Math.floor(Math.log10(num));
var round = Math.pow(10, pow);
var times = Math.floor(num / round);
var rest = Math.abs(num - (round * times));
var res = pow * (round==10 ? 1 : round / 10) * times;
if (num.toString()[0] == '9') res += rest;
if (rest < 9) return res;
else return res + number9Helper(rest);
}
function number9(num) {
var res = number9Helper(num);
res = res + (num.toString().split('9').length-1);
return res;
}
== Function below works but is slow ===
So, could something like this work for you:
for (var nines=0, i=1; i<=n; i++) nines += i.toString().split('9').length-1;
Basically, there are many way to achieve what you need, in the end it all depends how do you want to approach it.
You can test it with
function nines(n) {
for (var nines=0, i=1; i<=n; i++) nines += i.toString().split('9').length-1;
return nines;
}

function number9(n) {
if (n < 8) {
return 0
};
if (n === 9) {
return 1
};
if (n > 10) {
let str = ''
for (let i = 9; i <= n; i++) {
str += String(i)
}
return str.match(/[9]/g).length
}
}

Related

why is prime-factorization-function not working properly?

I made a simple function in js that took one argument n, and factored it down to primes. However, when n is a product of duplicates of primes, it does not add the duplicates to the array of factors. For example the number 28. 28 is equal to 2*2*7 = 2^2 * 7. If I run my function factor(n) with n = 28, I want to get the following result: [2,2,7]. Instead, I get [2,7]. Can someone help me fix this??? Here's the function in js:
function factor(n) {
var factors = []
for (var i = 2; i < n; i++) {
if (divisible(n,i)) {
if (isPrime(i)) {
factors.push(i)
}
factor(i)
}
}
console.log(factors)
}
THANKS!
const primeFactors = N => {
const smallestFactor = n => {
if (n % 2 === 0) return 2;
for (let k = 3; k * k <= n; k+= 2) if (n % k === 0) return k;
return n;
}
let factors = [];
let val = N;
while (val !== 1) {
let factor = smallestFactor(val);
factors.push(factor);
val /= factor;
}
return factors;
}
console.log(primeFactors(28));

I'm trying to raise numbers to their consecutive powers and my code isn't working

https://codepen.io/aholston/pen/ZJbrjd
The codepen link has commented code as well as actual instructions in HTML
Otherwise.... what I ultimately have to do is write a function that takes two params(a and b) and takes all the numbers between those two params (a-b) and put every number that can be added to the consecutive fowers and be equal to that number into a new array. Ex: 89 = 8^1 + 9^2 = 89 or 135 = 1^1 + 3^2 + 5^3 = 135
function sumDigPow(a, b) {
// Your code here
var numbers = [];
var checkNum = [];
var finalNum = [];
var total = 0;
for (var i = 1; i <= b; i++) {
if (i >= a && i <= b) {
numbers.push(i);
}
}
for (var x = 0; x < numbers.length; x++) {
var checkNum = numbers[x].toString().split('');
if (checkNum.length == 1) {
var together = parseInt(checkNum);
finalNum.push(together);
} else if (checkNum.length > 1) {
var together = checkNum.join('');
var togNumber = parseInt(together);
for (var y = checkNum.length; y > 0; y--) {
total += Math.pow(checkNum[y - 1], y);
}
if (total == togNumber) {
finalNum.push(togNumber);
}
}
}
return finalNum;
}
try this:
function listnum(a, b) {
var finalNum = [];
for (var i = a; i <= b; i++) {
var x = i;
var y = i;
var tot = 0;
j = i.toString().length;
while (y) {
tot += Math.pow((y%10), j--);
y = Math.floor(y/10);
}
if (tot == x)
finalNum.push(i);
}
return finalNum;
}
console.log(listnum(1, 200));
Okay, after debugging this is what I learned.
for (var y = checkNum.length; y > 0; y--) {
total += Math.pow(checkNum[y - 1], y);
}
if (total == togNumber) {
finalNum.push(togNumber);
}
}
}
return finalNum;
}
Everytime this loop happened, I neglected to reset the 'total' variable back to 0. So I was never getting the right answer for my Math.pow() because my answer was always adding to the previous value of total. In order to fix this, I added var total = 0; after i decided whether or not to push 'togNumber' into 'finalNum.' So my code looks like this..
for (var y = checkNum.length; y > 0; y--) {
total += Math.pow(checkNum[y - 1], y);
}
if (total == togNumber) {
finalNum.push(togNumber);}
}
var total = 0;
}
return finalNum;
}

"Steps in Primes" of Codewars

I got problems when doing "Steps in Primes" of Codewars.
Make function step(g,m,n) which g=step >= 2 , m=begin number >=2,
n=last number>= n. Step(g,m,n) will return the first match [a,b] which
m < a,b is prime < n and a+g=b.
I did right in basic test cases but when i submit , i got infinity loop somewhere. Can anyone give me suggestion?
function isInt(n) {
if(typeof n==='number' && (n%1)===0) {
return true;
}
else return false;
}
function step(g, m, n) {
if(isInt(g) && isInt(m) && isInt(n) &&g >= 2 && m >= 2 && n>=m) {
var p=[];
var ans=[];
for (var temp=m; temp<=n;temp++)
{
var a=0;
for (var chk=2; chk<temp-1;chk++)
if (temp%chk===0) a++;
if (a===0) p.push(temp);
}
for (var a=0;a<p.length-1;a++)
{
for (var b=a+1;b<p.length;b++)
if (p[b]===(p[a]+g)) return [p[a],p[b]];
}
}
return "nil";
}
this code might help you
function gap(g, m, n) {
var prime-numbers = [];
var final = [];
var prime;
for (var i = m; i <= n; i++) {
prime = true;
for (var j = 2; j < i / 2; j++) {
if (i % j === 0) {
prime = false;
}
}
if (prime) {
prime-numbers.push(i);
}
}
prime-numbers.forEach(function(prime, index) {
if (prime + g === prime-numbers[index + 1]) {
final.push(prime, prime-numbers[index + 1]);
}
});
if (final) return final.slice(0,2);
else return null;
}

Project Euler #23 in JS

My results for numbers between 1 and 28321 (limit)
sum of all numbers: 395465626
sum of all abundant numbers: 392188885
sum of all non abundant numbers: 3276741 (correct answer is 4179871)
var divisors = function(number){
sqrtNumber = Math.sqrt(number);
var sum = 1;
for(var i = 2; i<= sqrtNumber; i++)
{
if (number == sqrtNumber * sqrtNumber)
{
sum += sqrtNumber;
sqrtNumber--;
}
if( number % i == 0 )
{
sum += i + (number/i);
}
}
if (sum > number) {return true;}
else {return false;}
};
var abundent = [], k = 0;
var upperLimit = 28123;
for (var i = 1; i <= upperLimit; i++)
{
if (divisors(i))
{abundent[k] = i; k++};
}
var abundentCount = abundent.length;
var canBeWrittenAsAbundant = [];
for (var i = 0; i < abundentCount; i++){
for (var j = i; j < abundentCount; j++){
if (abundent[i] + abundent[j] <= upperLimit){canBeWrittenAsAbundant[abundent[i]+abundent[j]] = true;}
else {
break;
}
}
}
for (i=1; i <= upperLimit; i++){
if (canBeWrittenAsAbundant[i] == true){continue;}
else {canBeWrittenAsAbundant[i] = false;}
}
var sum = 0;
for (i=1; i <= upperLimit; i++)
{
if (!canBeWrittenAsAbundant[i]){
sum += i;
}
}
console.log(sum);
I'm using http://www.mathblog.dk/project-euler-23-find-positive-integers-not-sum-of-abundant-numbers/ as guidance, but my results are different. I'm a pretty big newb in the programming community so please keep that in mind.
You do not need to calculate the sum of all numbers using a cycle, since there is a formula, like this:
1 + 2 + ... + number = (number * (number + 1)) / 2
Next, let's take a look at divisors:
var divisors = function(number){
sqrtNumber = Math.sqrt(number);
var sum = 1;
for(var i = 2; i<= sqrtNumber; i++)
{
if (number == sqrtNumber * sqrtNumber)
{
sum += sqrtNumber;
sqrtNumber--;
}
if( number % i == 0 )
{
sum += i + (number/i);
}
}
if (sum > number) {return true;}
else {return false;}
};
You initialize sum with 1, since it is a divisor. However, I do not quite understand why do you iterate until the square root instead of the half of the number. For example, if you call the function for 100, then you are iterating until i reaches 10. However, 100 is divisible with 20 for example. Aside of that, your function is not optimal. You should return true as soon as you found out that the number is abundant. Also, the name of divisors is misleading, you should name your function with a more significant name, like isAbundant. Finally, I do not understand why do you decrease square root if number happens to be its exact square and if you do so, why do you have this check in the cycle. Implementation:
var isAbundant = function(number) {
var sum = 1;
var half = number / 2;
for (var i = 2; i <= half; i++) {
if (number % i === 0) {
sum += i;
if (sum > number) {
return true;
}
}
}
return false;
}
Note, that perfect numbers are not considered to be abundant by the function.
You do not need to store all numbers, since you are calculating aggregate data. Instead, do it like this:
//we assume that number has been initialized
console.log("Sum of all numbers: " + ((number * (number + 1)) / 2));
var abundantSum = 0;
var nonAbundantSum = 0;
for (var i = 0; i <= number) {
if (isAbundant(i)) {
abundantSum += i;
} else {
nonAbundantSum += i;
}
}
console.log("Sum of non abundant numbers: " + nonAbundantSum);
console.log("Sum of abundant numbers: " + abundantSum);
Code is not tested. Also, beware overflow problems and structure your code.
Below is the Corrected Code for NodeJS..
var divisors = function (number) {
sqrtNumber = Math.sqrt(number);
var sum = 1;
var half = number / 2;
for (var i = 2; i <= half; i++) {
if (number % i === 0) { sum += i; }
}
if (sum > number) { return true; }
else { return false; }
};
var abundent = [], k = 0;
var upperLimit = 28123;
for (var i = 1; i <= upperLimit; i++) {
if (divisors(i)) { abundent[k] = i; k++ };
}
var abundentCount = abundent.length;
var canBeWrittenAsAbundant = [];
for (var i = 0; i < abundentCount; i++) {
for (var j = i; j < abundentCount; j++) {
if (abundent[i] + abundent[j] <= upperLimit) { canBeWrittenAsAbundant[abundent[i] + abundent[j]] = true; }
else {
break;
}
}
}
for (i = 1; i <= upperLimit; i++) {
if (canBeWrittenAsAbundant[i] == true) { continue; }
else { canBeWrittenAsAbundant[i] = false; }
}
var sum = 0;
for (i = 1; i <= upperLimit; i++) {
if (!canBeWrittenAsAbundant[i]) {
sum += i;
}
}
console.log(sum);

for loop number sequence of (1,1,2,2,3,3, etc.)

I looked it up and this pattern is Hofstadter Female sequence. The equations are:
M(n) = n-F(M(n-1))
F(n) = n-M(F(n-1))
but I'm not sure how to put that into code.
So far I have:
while () {
_p++
_r++
if (_p % 2 === 0) {
_r = _p - 1;
}
}
Any help?
Without memoization:
function F(n)
{
return 0 < n ? n - M(F(n-1)) : 1
}
function M(n)
{
return 0 < n ? n - F(M(n-1)) : 0
}
var N = 10;
var f = [];
var m = [];
for (var i = 0; i <= N; ++i) {
f.push(F(i));
m.push(M(i));
}
console.log('F: ' + f.join(','))
console.log('M: ' + m.join(','))
Output:
F: 1,1,2,2,3,3,4,5,5,6,6
M: 0,0,1,2,2,3,4,4,5,6,6
http://jsfiddle.net/KtGBg/1/
Recursion should be avoided, if possible, so you can cache the already-calculated values for F(n) and M(n) :
var f = new Array();
var m = new Array();
function F(n){
if(f[n] != undefined) {
return f[n];
}
if (n==0) {
value = 1;
} else {
value = n - M(F(n-1));
}
f[n] = value;
return value;
}
function M(n){
if(m[n] != undefined) {
return m[n];
}
if (n==0) {
value = 0;
} else {
value = n - F(M(n-1));
}
m[n] = value;
return value;
}
This yields a much faster result for greater numbers (try it with 10000)
how about:
function F(n){
if (n==0) return 1
else return n - M(F(n-1))
}
function M(n){
if (n==0) return 0
else return n - F(M(n-1))
}
var str = ""
for(var i=0; i<=10; i++) str += F(i) + ", "
console.log(str.substr(0,str.length-2))
Similar to GaborSch's answer, you could use Doug Crockford's memoizer function, which can be found in Chapter 4 of Javascript: The Good Parts. Using memoization took the calculation time for the first 150 terms of the male and female Hofstadter sequences down to 256 ms as compared to almost 8 seconds without memoization.
var memoizer = function (memo, formula) {
var recur = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = formula(recur, n);
memo[n] = result;
}
return result;
};
return recur;
};
var maleHofstadter = memoizer([0], function (recur, n) {
return n - femaleHofstadter(recur(n-1));
});
var femaleHofstadter = memoizer([1], function (recur, n) {
return n - maleHofstadter(recur(n-1));
});
var N = 150;
var f = [];
var m = [];
for (var i = 0; i <= N; ++i) {
f.push(femaleHofstadter(i));
m.push(maleHofstadter(i));
}
console.log('F: ' + f.join(','));
console.log('M: ' + m.join(','));

Categories