What is a lucky number?
So we are going to create some code which I used as a challenge to the members of a Discord server I'm in. The challenge had the following criteria:
A lucky number is defined as any number that has a '6' or an '8' in it. A number with neither of these numbers, or both, is unlucky.
Create a program that, given two numbers L and R, works out the number of lucky numbers between those two values
The tough version, is to do this without strings
Calculating, with strings
So, the code to do this by using strings is pretty straightforward, as you might have guessed:
function countLuckyNumbers(L, R) {
let count = 0;
for (let i = L; i <= R; i++) {
let numberString = i.toString();
if (numberString.includes("6") && !numberString.includes("8")) {
count++;
} else if (numberString.includes("8") && !numberString.includes("6")) {
count++;
}
}
return count;
}
This code:
Sets a
count
to 0Turns the number to a string with the
toString()
methodUses the
includes()
method to see if the string either includes 6 and not 8, or 8 and not 6, and will increase the counter by 1 if it sees thisBecause we are not counting up for 6 and 8 or neither, it will not count these numbers
Return the
count
For anyone with experience of JS, this should be fairly straightforward, assuming you know the methods to use
Calculating, without strings
This however is harder. We are effectively looking at the number still, but because we cannot use strings, we must think a little harder.
Here is the code I came up with, and I will explain it:
function countLuckyNumbers(L, R) {
let count = 0;
for (let i = L; i <= R; i++) {
let hasSix = false;
let hasEight = false;
let num = i;
// Extract each digit of the number and check if it is 6 or 8
while (num > 0) {
let digit = num % 10;
if (digit === 6) {
hasSix = true;
} else if (digit === 8) {
hasEight = true;
}
num = Math.floor(num / 10);
}
// Check if the number is a lucky number and increment the count if it is
if (hasSix && !hasEight || hasEight && !hasSix) {
count++;
}
}
return count;
}
Some variable initialisation at the start, but nothing fancy.
let hasSix = false;
let hasEight = false;
let num = i;
Now for the clever part:
while (num > 0) {
let digit = num % 10;
if (digit === 6) {
hasSix = true;
} else if (digit === 8) {
hasEight = true;
}
num = Math.floor(num / 10);
}
What I'm doing here is letting the digit
, or the right most value, be the one I look at.
If this is a 6, then I set hasSix
to true
, and the same for hasEight
.
I then, at the end, use the Math.floor()
method to get rid of the digit.
Here is a better explanation of what is happening at each step:
An unlucky number
// let's use 567 and 568 as an example, 568 first
while(num > 0) { // num is 568 so this is false
let digit = num % 10
// 568 % 10 = 8, because the % operator gives the remainder of any number left when dividing these 2 numbers by 10
...
if(digit === 8) {
hasEight = true;
}
// because the digit is 8, we have set the hasEight boolean to true
num = Math.floor(num / 10);
// 568 / 10 = 56.8, and the floor() method will get rid of the decimal and just give us 56, so now we are going through the loop with 56
while(num > 0) { // num is 56 so this is false
let digit = num % 10
// 56 % 10 = 6
...
if(digit === 6) {
hasSix = true;
}
// digit is 6 so this will set the hasSix boolean to true
num = Math.floor(num / 10);
// 56 / 10 = 5.6 which just resolves to 5 with the floor() method
// and now I hope you can see the last time round, it'll be 5, which won't satisfy either argument, and then when it gets to the end, the floor() method will make num = 0, which will break the loop. we now move onto the next part:
if (hasSix && !hasEight || hasEight && !hasSix) {
count++;
}
// hasSix and hasEight are true, which means this will return false, and won't increase the count, making it an UNLUCKY number
A lucky number
while(num > 0) { // num is 567 so this is false
let digit = num % 10
// 567 % 10 = 7, because the % operator gives the remainder of any number left when dividing these 2 numbers by 10
// because the digit is 7, this is false and will skip both checking for 6 and 8
num = Math.floor(num / 10);
// 567 / 10 = 56.7, and the floor() method will get rid of the decimal and just give us 56, so now we are going through the loop with 56
while(num > 0) { // num is 56 so this is false
let digit = num % 10
// 56 % 10 = 6
...
if(digit === 6) {
hasSix = true;
}
// digit is 6 so this is of course, true
num = Math.floor(num / 10);
// 56 / 10 = 5.6 which just resolves to 5 with the floor() method
// and now I hope you can see the last time round, it'll be 5, which won't satisfy either argument, and then when it gets to the end, the floor() method will make num = 0, which will break the loop. we now move onto the next part:
if (hasSix && !hasEight || hasEight && !hasSix) {
count++;
}
// hasSix is true, but hasEight is now false, so this will add 1 number to the count
In summary
I hope this explained it to those who struggled with the challenge. Remember, we learn when we struggle, as long as we learn where we went wrong, record our mistakes and move forward.
I hope you enjoyed this look into how to solve a problem in an unconventional way, and please comment if you need some help with any part of this!
Appreciate each and every one of you who stops by to read my goings on! ❤️