2180. Count Integers With Even Digit Sum
Problem Description
The task is to find and count all the positive integers up to a given number num
whose digits add up to an even sum. For instance, if num
is 13, the number 12 would be counted because its digits 1 + 2 equals 3, which is an odd total, and hence its digit sum is not even.
The challenge is to compute the number of these integers efficiently, without having to check each number individually, since that would be too slow for large values of num
.
Intuition
The solution takes advantage of patterns in numbers and their sums. The key observations to arrive at the solution approach are:
-
Every group of ten numbers (0-9, 10-19, etc.) contains exactly five numbers with an even digit sum. This holds because within any such sequence, the sum of the digits changes in a predictable way when moving from one number to the next: the ones place increases by one until it resets at zero when it hits 10, and then the process repeats.
-
By considering the tens place separately, the solution calculates how many complete tens are in the number
num
. Multiply that count by 5 (since there are five numbers with an even digit sum in each group of ten) to get a baseline count. -
Adjust the baseline count based on the remainder of
num
when divided by 10 (the last digit ofnum
), and whether the sum of the tens digits is odd or even.
The formula ans = num // 10 * 5 - 1
starts by calculating the baseline even digit sum count, then subtracts 1 to adjust for the starting point (as the sequence starts at 0, not 1).
Next, the code calculates the sum of the tens place digits to determine if the sum, including the ones place of the original num
, is even or odd. Depending on this result and the value of the last digit of num
, the final answer (ans
) must be corrected.
Learn more about Math patterns.
Solution Approach
The provided Python solution uses mathematical reasoning rather than brute force iteration over every number up to num
. Here's a detailed breakdown of the implementation:
-
First, it calculates the number of complete tens in
num
—this tells us how many groups of ten we have to deal with. Each group of ten has exactly five numbers with an even digit sum, hencenum // 10 * 5
. This gives us a preliminary count. -
It subtracts 1 from this count by doing
ans = num // 10 * 5 - 1
because the sequence we are counting starts from 1 and not 0. For example, ifnum
is 20, without the subtraction, we would count from 0 to 19, but we actually need to count from 1 to 20. -
Then the algorithm calculates the sum of the tens place digits with the snippet:
x, s = num // 10, 0 while x: s += x % 10 x //= 10
This loops through each digit of
num / 10
and adds it tos
. The significance of this sum is to determine if the sum of all digits besides the last digit is odd or even, which influences the count adjustment in the subsequent step. -
Finally, the adjustment is done with the line:
ans += (num % 10 + 2 - (s & 1)) >> 1
Here's what happens in this line:
-
num % 10
gives us the last digit ofnum
. -
The expression
(s & 1)
gives us 1 if the sum of tens place digitss
is odd, and 0 if it's even. -
By adding 2 and then subtracting
(s & 1)
, we're effectively deciding whether to add 1 or 2 to the finalans
. This accounts for whether the sum will turn even after including the last digit. -
The
>> 1
is a bitwise right shift which divides the number by 2, discarding the remainder. This is used to finally adjust the answer correctly, accounting for the fact that only half of the adjustments (whether we add 1 or 2) result in an even total digit sum.
-
The key algorithmic patterns used in this solution are mathematical counting and digit manipulation, along with efficient arithmetic operations that replace the need for any complex data structures.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
To illustrate the solution approach, let's consider the number num = 23
. We want to find how many positive integers less than or equal to 23 have a digit sum that is even.
Following the steps outlined in the solution approach:
-
We first calculate the number of complete tens in 23, which is
2
(from23 // 10
). Since each group of 10 has exactly five numbers with an even digit sum, this gives us2 * 5 = 10
as our preliminary count. -
Now, we subtract 1 because we are counting from 1 rather than starting from 0. The count becomes
10 - 1 = 9
. -
Next, we determine the sum of the tens place digits:
23 // 10
gives us2
.- Since
2
is less than10
, the loop terminates after adding2
tos
. - The sum of the tens place digits is
s = 2
, which is even.
-
The last digit of
num
(23) is3
(23 % 10
). -
Finally, we make the adjustment:
s & 1
will evaluate to0
since2
(the sum of tens place digits) is even.- The correction
(num % 10 + 2) >> 1
equals(3 + 2) >> 1
, which simplifies to5 >> 1
or, in other terms,5 // 2
, which equals2
.
-
Since the tens place sum
s
is even, there's no need to further adjust the result for this case. -
Adding the correction to our count gives
9 + 2 = 11
. Therefore, there are 11 numbers less than or equal to 23 with an even digit sum.
To verify our method, we can manually count the numbers with even digit sums up to 23:
- Even digit sum numbers: 2, 4, 6, 8, 11, 13, 15, 17, 20, 22, 24 (treating
24
as2
and4
since we're looking at numbers up to23
) - Count of even digit sum numbers: 11
The manual count confirms that our method yields the correct result.
Solution Implementation
1class Solution:
2 def countEven(self, num: int) -> int:
3 # Initial calculation: every group of 10 numbers contains exactly 5 even numbers
4 # If 'num' is 58, then there would be (58 // 10) which is 5 groups of 10,
5 # each group contributing 5 even numbers, hence 5 * 5 even numbers
6 even_numbers_count = (num // 10) * 5
7
8 # Adjusting the calculation if the sum of digits in 'num'
9 # makes 'num' itself an even number, this will subtract one from the count.
10 even_numbers_count -= 1
11
12 # Now calculate the sum of the digits for the tens place and greater.
13 # This is to help us determine if the last digit contributes an even or odd number.
14 tens_and_above = num // 10
15 sum_of_digits = 0
16 while tens_and_above:
17 sum_of_digits += tens_and_above % 10
18 tens_and_above //= 10
19
20 # Calculate the adjustment needed for the last digit contribution.
21 # If the sum of digits (tens place and above) is even, then an
22 # additional even number can be included if the ones place is 1-9, otherwise it's 0-8.
23 # If the sum of digits is odd, then it's off by one either way.
24 # The adjustment uses bitwise operation to quickly determine if
25 # we need to add one more to the count.
26 last_digit_adjustment = ((num % 10) + 2 - (sum_of_digits & 1)) >> 1
27
28 # Apply the last digit adjustment to the even numbers count.
29 even_numbers_count += last_digit_adjustment
30
31 # Return the final count of even numbers.
32 return even_numbers_count
33
1class Solution {
2 // Method to count the number of even digit sum numbers up to a given number
3 public int countEven(int num) {
4 // Initialize a counter for the even sum numbers
5 int evenSumCount = 0;
6
7 // Loop through all numbers from 1 up to and including 'num'
8 for (int currentNumber = 1; currentNumber <= num; ++currentNumber) {
9 // Variable to store the sum of the digits of the current number
10 int digitSum = 0;
11
12 // Calculate the sum of the digits of 'currentNumber'
13 for (int x = currentNumber; x > 0; x /= 10) {
14 digitSum += x % 10; // Add the rightmost digit to 'digitSum'
15 }
16
17 // If the digit sum is even, increment the even sum count
18 if (digitSum % 2 == 0) {
19 ++evenSumCount;
20 }
21 }
22
23 // Return the total count of numbers with an even digit sum
24 return evenSumCount;
25 }
26}
27
1class Solution {
2public:
3 int countEven(int num) {
4 // Calculate the number of even numbers by integer division by 10 and then multiply by 5.
5 // Subtracted by 1 because the range is from 1 to num-1.
6 int evenCount = (num / 10) * 5 - 1;
7
8 // Calculate the sum of the digits in the quotient when num is divided by 10
9 // This sum is used to determine if the last digit will result in an even total sum.
10 int digitSum = 0;
11 for (int x = num / 10; x > 0; x /= 10) {
12 digitSum += x % 10;
13 }
14
15 // Check if the last digit in num contributes to an even or odd sum.
16 // If digitSum is even, then (num%10 + 2) contributes to having an odd total sum if num's last digit is even.
17 // If digitSum is odd, then (num%10 + 2) contributes to having an even total sum if num's last digit is even.
18 // The right shift by 1 at the end is essentially dividing by 2, which works to calculate the final adjustment.
19 evenCount += ((num % 10) + 2 - (digitSum & 1)) >> 1;
20
21 return evenCount;
22 }
23};
24
1function countEven(num: number): number {
2 // Calculate the number of even tens before the given num
3 let evenCount = Math.floor(num / 10) * 5 - 1;
4
5 // Initialize the sum of digits variable for tens place
6 let digitSum = 0;
7
8 // Calculate the sum of digits in the tens place and above
9 for (let x = Math.floor(num / 10); x; x = Math.floor(x / 10)) {
10 digitSum += x % 10;
11 }
12
13 // Check the last digit of num and the parity of digitSum to determine
14 // if an additional even number should be counted
15 evenCount += ((num % 10) + 2 - (digitSum & 1)) >> 1;
16
17 // Return the total count of even numbers before and including num
18 return evenCount;
19}
20
Time and Space Complexity
The given Python code implements an algorithm that counts how many integers from 1
to num
have an even digit sum. The time complexity and space complexity of this algorithm are analyzed as follows:
Time Complexity
- The first line within the
countEven
method,ans = num // 10 * 5 - 1
, involves a few constant-time arithmetic operations (integer division, multiplication, and subtraction) and therefore executes inO(1)
time. - The while-loop iterates over the number of digits in
num // 10
, which is proportional to the logarithm ofnum
. Hence, the loop runs inO(log(num))
time. - Inside the loop, again only constant-time operations—modulus, integer division, and accumulation into
s
—are performed. - The last line outside the loop involves a few more constant-time arithmetic operations, including modulus, addition, bitwise AND, subtraction, and bit-shifting.
Overall, the most time-consuming part of the algorithm is the while-loop, so the time complexity is O(log(num))
.
Space Complexity
For space complexity:
- The method uses a fixed number of integer variables
ans
,x
,s
, and those used for simple calculations. This occupies a constant amount of space. - No additional data structures that grow with the input size are used.
- The space taken to store the intermediate results does not depend on the size of
num
, as it is only affected by the number of digits innum
which is logarithmic in size.
Therefore, the space complexity of the algorithm is O(1)
as it requires a constant amount of space regardless of the input size.
Learn more about how to find time and space complexity quickly using problem constraints.
What's the output of running the following function using input 56
?
1KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13 def dfs(path, res):
14 if len(path) == len(digits):
15 res.append(''.join(path))
16 return
17
18 next_number = digits[len(path)]
19 for letter in KEYBOARD[next_number]:
20 path.append(letter)
21 dfs(path, res)
22 path.pop()
23
24 res = []
25 dfs([], res)
26 return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2 '2', "abc".toCharArray(),
3 '3', "def".toCharArray(),
4 '4', "ghi".toCharArray(),
5 '5', "jkl".toCharArray(),
6 '6', "mno".toCharArray(),
7 '7', "pqrs".toCharArray(),
8 '8', "tuv".toCharArray(),
9 '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13 List<String> res = new ArrayList<>();
14 dfs(new StringBuilder(), res, digits.toCharArray());
15 return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19 if (path.length() == digits.length) {
20 res.add(path.toString());
21 return;
22 }
23 char next_digit = digits[path.length()];
24 for (char letter : KEYBOARD.get(next_digit)) {
25 path.append(letter);
26 dfs(path, res, digits);
27 path.deleteCharAt(path.length() - 1);
28 }
29}
30
1const KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13 let res = [];
14 dfs(digits, [], res);
15 return res;
16}
17
18function dfs(digits, path, res) {
19 if (path.length === digits.length) {
20 res.push(path.join(''));
21 return;
22 }
23 let next_number = digits.charAt(path.length);
24 for (let letter of KEYBOARD[next_number]) {
25 path.push(letter);
26 dfs(digits, path, res);
27 path.pop();
28 }
29}
30
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!