Open In App

Count Valid Numbers with Equal Digit Frequencies

Last Updated : 24 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an integer n (1 <= n <= 1010), count the number of valid numbers in the range [1, n] (inclusive).

Note: A number is called valid if digits 2, 4, and 8 occur in it with equal nonzero frequencies. For example, numbers 248, 284824, and 2148 are valid, whereas numbers 3456 (different frequencies) and 356 (zero frequencies) are not.

Examples:

Input: n = 300
Output: 2
Explanation: 248 and 284 are the only valid integers in range.

Input: n = 1248
Output: 7
Explanation: 248, 284, 428, 482, 824, 842, 1248 are the valid integers in range.

Approach: To solve the problem follow the below idea:

Use digit DP to count the numbers in the range [0, n] where the count of digits 2, 4, and 8 are all equal and greater than zero.

Follow the steps to solve the problem:

  • It iterates through the digits of the input number n from left to right, considering each digit keeping track of the counts of the digits 2, 4, and 8 using the variables two, four, and eight.
  • By using memoization to store intermediate results for avoiding redundant calculations and overlapping.
  • For each digit we recursively explores two possibilities either the current digit is less than the corresponding digit in n or it’s equal.
  • Then now If the flag is not set (meaning the current digit can be less than the corresponding digit in n), it considers all possible digits less than the current digit and updates the counts of 2s, 4s, and 8s accordingly.
  • If the flag is set (meaning the current digit must be equal to the corresponding digit in n), it considers all possible digits from 0 to 9.
  • The base case checks whether all three counts (two, four, and eight) are equal, greater than zero, and not equal to 0. If this condition falls true the current number is considered valid.
  • Finally returns the count of valid numbers found during this recursion.

Below is the C++ implementation of the above approach:

C++




// C++ code for the above approach:
#include <cstring>
#include <iostream>
using namespace std;
 
int dp[10][10][10][10][2];
 
int solve(int ind, int two, int four, int eight, int flag,
          string& s)
{
    if (ind == s.size()) {
        if (two == four && eight == four && two != 0
            && four != 0 && eight != 0)
            return 1;
        else
            return 0;
    }
 
    if (dp[ind][two][four][eight][flag] != -1)
        return dp[ind][two][four][eight][flag];
 
    int ans = 0;
    if (!flag) {
        for (int i = 0; i < s[ind] - '0'; i++) {
            ans += solve(ind + 1, two + (i == 2),
                         four + (i == 4), eight + (i == 8),
                         1, s);
        }
        ans += solve(ind + 1, two + ((s[ind] - '0') == 2),
                     four + ((s[ind] - '0') == 4),
                     eight + ((s[ind] - '0') == 8), 0, s);
    }
    else {
        for (int i = 0; i < 10; i++) {
            ans += solve(ind + 1, two + (i == 2),
                         four + (i == 4), eight + (i == 8),
                         1, s);
        }
    }
    return dp[ind][two][four][eight][flag] = ans;
}
 
// Driver code
int main()
{
    int n = 1248;
    memset(dp, -1, sizeof(dp));
    string s1 = to_string(n);
 
    // Function Call
    cout << solve(0, 0, 0, 0, 0, s1) << endl;
    return 0;
}


Java




// Java code for the above approach:
 
class GFG {
 
    static int[][][][][] dp = new int[10][10][10][10][2];
 
    public static int solve(int ind, int two, int four,
                            int eight, int flag, String s)
    {
        if (ind == s.length()) {
            if (two == four && eight == four && two != 0
                && four != 0 && eight != 0) {
                return 1;
            }
            else {
                return 0;
            }
        }
 
        if (dp[ind][two][four][eight][flag] != -1) {
            return dp[ind][two][four][eight][flag];
        }
 
        int ans = 0;
 
        if (flag == 0) {
            for (int i = 0; i < s.charAt(ind) - '0'; i++) {
                ans += solve(
                    ind + 1, two + (i == 2 ? 1 : 0),
                    four + (i == 4 ? 1 : 0),
                    eight + (i == 8 ? 1 : 0), 1, s);
            }
 
            ans += solve(
                ind + 1,
                two + ((s.charAt(ind) - '0') == 2 ? 1 : 0),
                four + ((s.charAt(ind) - '0') == 4 ? 1 : 0),
                eight
                    + ((s.charAt(ind) - '0') == 8 ? 1 : 0),
                0, s);
        }
        else {
            for (int i = 0; i < 10; i++) {
                ans += solve(
                    ind + 1, two + (i == 2 ? 1 : 0),
                    four + (i == 4 ? 1 : 0),
                    eight + (i == 8 ? 1 : 0), 1, s);
            }
        }
 
        return dp[ind][two][four][eight][flag] = ans;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int n = 1248;
 
        // Initializing dp array
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                for (int k = 0; k < 10; k++) {
                    for (int l = 0; l < 10; l++) {
                        dp[i][j][k][l][0] = -1;
                        dp[i][j][k][l][1] = -1;
                    }
                }
            }
        }
 
        String s1 = Integer.toString(n);
 
        // Function Call
        System.out.println(solve(0, 0, 0, 0, 0, s1));
    }
}
 
// This code is contributed by ragul21


Python3




# Define a recursive function to count the number of valid sequences
def solve(ind, two, four, eight, flag, s, dp):
    # Base case: If we've processed the entire string, check if it's valid
    if ind == len(s):
        if two == four == eight and two != 0 and four != 0 and eight != 0:
            return 1
        else:
            return 0
 
    # Check if the result for the current state is already cached in dp
    if dp[ind][two][four][eight][flag] != -1:
        return dp[ind][two][four][eight][flag]
 
    ans = 0
 
    # If we're not in a "flag" state (meaning we haven't encountered a digit
    # greater than the current one), try all digits less than s[ind]
    if not flag:
        for i in range(int(s[ind])):
            ans += solve(ind + 1, two + (i == 2), four + (i == 4), eight + (i == 8), 1, s, dp)
        # Continue with the same digit as s[ind]
        ans += solve(ind + 1, two + (int(s[ind]) == 2), four + (int(s[ind]) == 4), eight + (int(s[ind]) == 8), 0, s, dp)
    else:
        # If we are in a "flag" state, try all possible digits (0-9)
        for i in range(10):
            ans += solve(ind + 1, two + (i == 2), four + (i == 4), eight + (i == 8), 1, s, dp)
 
    # Cache the result and return it
    dp[ind][two][four][eight][flag] = ans
    return ans
 
# Define the input number
n = 1248
 
# Initialize the cache (dp) with -1
dp = [[[[[-1 for _ in range(2)] for _ in range(10)] for _ in range(10)] for _ in range(10)] for _ in range(5)]
 
# Convert the number to a string for processing
s1 = str(n)
 
# Call the recursive function to count valid sequences
result = solve(0, 0, 0, 0, 0, s1, dp)
 
# Print the result
print(result)


C#




using System;
 
class Program
{
    static int[,,,,] dp;
 
    static int Solve(int ind, int two, int four, int eight, int flag, string s)
    {
        if (ind == s.Length)
        {
            if (two == four && four == eight && two != 0 && four != 0 && eight != 0)
                return 1;
            else
                return 0;
        }
 
        if (dp[ind, two, four, eight, flag] != -1)
            return dp[ind, two, four, eight, flag];
 
        int ans = 0;
 
        if (flag == 0)
        {
            for (int i = 0; i < int.Parse(s[ind].ToString()); i++)
            {
                ans += Solve(ind + 1, two + (i == 2 ? 1 : 0), four + (i == 4 ? 1 : 0), eight + (i == 8 ? 1 : 0), 1, s);
            }
            ans += Solve(ind + 1, two + (s[ind] == '2' ? 1 : 0), four + (s[ind] == '4' ? 1 : 0), eight + (s[ind] == '8' ? 1 : 0), 0, s);
        }
        else
        {
            for (int i = 0; i < 10; i++)
            {
                ans += Solve(ind + 1, two + (i == 2 ? 1 : 0), four + (i == 4 ? 1 : 0), eight + (i == 8 ? 1 : 0), 1, s);
            }
        }
 
        dp[ind, two, four, eight, flag] = ans;
        return ans;
    }
 
    static void Main()
    {
        int n = 1248;
        string s1 = n.ToString();
 
        dp = new int[s1.Length + 1, 10, 10, 10, 2];
        for (int i = 0; i <= s1.Length; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                for (int k = 0; k < 10; k++)
                {
                    for (int l = 0; l < 10; l++)
                    {
                        for (int m = 0; m < 2; m++)
                        {
                            dp[i, j, k, l, m] = -1;
                        }
                    }
                }
            }
        }
 
        int result = Solve(0, 0, 0, 0, 0, s1);
        Console.WriteLine(result);
    }
}
// Code is Contributed By Block_Cipher


Javascript




// JavaScript code for the above approach:
 
let dp = new Array(10)
  .fill(null)
  .map(() =>
    new Array(10)
      .fill(null)
      .map(() =>
        new Array(10)
          .fill(null)
          .map(() =>
            new Array(10)
              .fill(null)
              .map(() => new Array(2).fill(-1))
          )
      )
  );
 
function solve(ind, two, four, eight, flag, s) {
  if (ind === s.length) {
    if (two === four && eight === four && two !== 0 && four !== 0 && eight !== 0) {
      return 1;
    } else {
      return 0;
    }
  }
 
  if (dp[ind][two][four][eight][flag] !== -1) {
    return dp[ind][two][four][eight][flag];
  }
 
  let ans = 0;
 
  if (flag === 0) {
    for (let i = 0; i < parseInt(s.charAt(ind)); i++) {
      ans += solve(
        ind + 1,
        two + (i === 2 ? 1 : 0),
        four + (i === 4 ? 1 : 0),
        eight + (i === 8 ? 1 : 0),
        1,
        s
      );
    }
 
    ans += solve(
      ind + 1,
      two + (parseInt(s.charAt(ind)) === 2 ? 1 : 0),
      four + (parseInt(s.charAt(ind)) === 4 ? 1 : 0),
      eight + (parseInt(s.charAt(ind)) === 8 ? 1 : 0),
      0,
      s
    );
  } else {
    for (let i = 0; i < 10; i++) {
      ans += solve(ind + 1, two + (i === 2 ? 1 : 0), four + (i === 4 ? 1 : 0), eight + (i === 8 ? 1 : 0), 1, s);
    }
  }
 
  return (dp[ind][two][four][eight][flag] = ans);
}
 
// Driver code
function main() {
  let n = 1248;
 
  // Initializing dp array
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
      for (let k = 0; k < 10; k++) {
        for (let l = 0; l < 10; l++) {
          dp[i][j][k][l][0] = -1;
          dp[i][j][k][l][1] = -1;
        }
      }
    }
  }
 
  let s1 = n.toString();
 
  // Function Call
  console.log(solve(0, 0, 0, 0, 0, s1));
}
 
// Execute the main function
main();
 
// This code is contributed by akshitaguprzj3


Output

7








Time Complexity: O(10^(log10(n))), number of recursive calls for string s of n length, which is O(log10(n)), at each level of recursion loop runs 10 times.
Auxiliary Space: O(n), as we are using 4D dp array.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads