Count of integers in a range which have even number of odd digits and odd number of even digits

Given a range [L, R], the task is to count the numbers which have even number of odd digits and odd number of even digits. For example,

  1. 8 has 1 even digit and 0 odd digit – Satisfies the condition since 1 is odd and 0 is even.
  2. 545 has 1 even digit and 2 odd digits – Satisfies the condition since 1 is odd and 2 is even.
  3. 4834 has 3 even digits and 1 odd digit – Does not satisfy the condition since there are odd numbers(i.e 1) of odd digits.

Examples:

Input: L = 1, R = 9
Output: 4
2, 4, 6 and 8 are the only integers from the
given range that satisfy the given conditions.

Input: L = 1, R = 19
Output: 4

Input: L = 123, R = 984
Output: 431

Approach:

  • Case 1
    There is a pattern in which these numbers occur between 1 and 10^{k} (where 1<=k<=18).
    Number of occurrences from

    • 1 – 10 and 1 – 100 are 4
    • 1 – 1000 and 1 – 10000 are 454
    • 1 – 10000 and 1 – 100000 are 45454

    and so on…

  • Case 2
    • If the number of digits in a number is even then it cannot satisfy the given condition because we need an odd number(of digits) and an even number(of digits) to satisfy our condition and odd number + even number is always odd
    • So if the number of digits for a given number(say n) is even then its number of occurrences from 1 is equal to the number of occurrences from 1 to largest 10^{k} (1<=k<=18) which is less than n
    • Example:
      Let n = 19, number of digits in 19 are 2
      Therefore number of occurrences from 1 – 19 = number of occurrences from 1 – 10 (since 10 the largest 10^{k} less than 19)

  • Case 3
    If number of digits for a given number(say n) are odd then number of occurrences between 10^{k}+1 and n is equal to

    where 10^{i} is the largest 10^{k} less than n.

Implementation: Now we now how to calculate the number of occurrences from 1 to given n. Therefore,
Number of occurrences from L to R = NumberOfOccurrencesUpto(R) – NumberOfOccurrencesUpto(L – 1) where L is not equal to 1.

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the approach
  
# Pattern table from Case 1
values = {
    1: 0,
    10: 4,
    100: 4,
    1000: 454,
    10000: 454,
    100000: 45454,
    1000000: 45454,
    10000000: 4545454,
    100000000: 4545454,
    1000000000: 454545454,
    10000000000: 454545454,
    100000000000: 45454545454,
    1000000000000: 45454545454,
    10000000000000: 4545454545454,
    100000000000000: 4545454545454,
    1000000000000000: 454545454545454,
    10000000000000000: 454545454545454,
    100000000000000000: 45454545454545454,
    1000000000000000000: 45454545454545454,
}
  
# Function that returns the number of 
# even and odd digits in val
def count_even_odd(val):
    even = odd = 0
    while val > 0:
        num = val % 10
        if num % 2 == 0:
            even += 1
        else:
            odd += 1
        val //= 10
  
    return even, odd
  
# Function that returns True if num 
# satisfies the given condition
def satisfies_condition(num):
    even, odd = count_even_odd(num)
    if even % 2 == 1 and odd % 2 == 0:
        return True
    return False
  
  
# Function to return the count of numbers 
# from 1 to val that satisfies the given condition
def count_upto(val):
  
    # If the value is already present in the
    # values dict
    if int(val) in values:
        return values[int(val)]
  
    # If the value is even
    # Case 2
    if len(val) % 2 == 0:
        return values[int('1' + '0' * (len(val) - 1))]
  
    val_len = len(val)
    count = values[int('1' + '0' * (val_len - 1))]
  
    # Now the problem is to count the desired
    # numbers from 10**(val_len-1) + 1 to val
    left_end = int('1' + '0' * (val_len - 1)) + 1
  
    # Case 3
    # Eliminating all the even numbers
    count += (int(val) - left_end) // 2
  
    if satisfies_condition(int(val)) or satisfies_condition(left_end):
        count += 1
    return count
  
  
if __name__ == '__main__':
  
    # Input L and R ( as a string )
    l, r = '123', '984'
  
    right = count_upto(r)
  
    left = 0
    if(left == '1'):
        left = 0
    else:
        left = count_upto(str(int(l)-1))
  
    print(right - left)

chevron_right


Output:

431

Time Complexity: O(logn)



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.