Building things that matter

Code Challenges

Count The Digit (Ruby)

It was a slow Sunday so decided to hit the next challenge on CodeWars

The Challenge

Take an integer n (n >= 0) and a digit d (0 <= d <= 9) as an integer. Square all numbers k (0 <= k <= n) between 0 and n. Count the numbers of digits d used in the writing of all the k**2. Call nb_dig (or nbDig or ...) the function taking n and d as parameters and returning this count.


n = 10, d = 1, the k*k are 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
We are using the digit 1 in 1, 16, 81, 100. The total count is then 4.

nb_dig(25, 1):
the numbers of interest are
1, 4, 9, 10, 11, 12, 13, 14, 19, 21 which squared are 1, 16, 81, 100, 121, 144, 169, 196, 361, 441
so there are 11 digits `1` for the squares of numbers between 0 and 25.

Note that 121 has twice the digit 1.

My Solution

Pretty straight forward, though no hashes in this one. Not to say I didn't consider ways I could use a hash to solve it (I may be obsessed).  But stuck with the arrays we start with, rocking some mapping and learning the speed difference between to_s and digits.

I identified two main things this function was going to be doing and I extracted those two actions into their own methods, square and split the values of our starting array and then counting the digits that match the parameter 'd.' 

One thing I found when attempting to solve this was that there is a speed difference between the two methods I attempted to look at the individual digits of the numbers generated. I originally started by doing something like this: { |x| x.to_s }

This did return the correct solution in the initial test cases, however, it did not execute fast enough to clear all 111 random tests in the challenge.  So even though I had solved it, I had to go back to refactor to optimize the solution to move faster. 

I was able to cut back on the number of iterations I was initially doing, however the thing that sped it up and executed fast enough to clear all 111 was using digits instead of the above to_s solution. Once I used digits, it cleared with no issues, thus providing a far-less-than-scientific benchmark test, but one I'll take nonetheless.  Plus digits allowed me to work with integers as they were without having to convert or do anything super odd or unnecessary. 

I then took this array I called digits on and passed it into my first custom method, square_split_values

This method actually does two things as indicated by it's name.  It squares the values and splits them into digits.  I had thought about changing this into two separate methods, one that squares the values and one that splits, but the actions were simple enough I opted to keep them both in the same method. 

My second method takes the array of digits after they have been split, and compares them against the 'd' parameter, and if they match, increments a counter to return the number of digits that match the 'd' parameter. 

I originally took each value and pushed into a new array I counted the length of, but given all I needed to do was count it's length, a counter seemed to make more sense and was more effective.  Had I needed to do anything more with that array then I would have stuck with that, but I didn't, so an incremental counter made more sense. 

Yay Sunday code challenges!




Robert Cornell