Welcome to Subscribe On Youtube

3747. Count Distinct Integers After Removing Zeros

Description

You are given a positive integer n.

For every integer x from 1 to n, we write down the integer obtained by removing all zeros from the decimal representation of x.

Return an integer denoting the number of distinct integers written down.

 

Example 1:

Input: n = 10

Output: 9

Explanation:

The integers we wrote down are 1, 2, 3, 4, 5, 6, 7, 8, 9, 1. There are 9 distinct integers (1, 2, 3, 4, 5, 6, 7, 8, 9).

Example 2:

Input: n = 3

Output: 3

Explanation:

The integers we wrote down are 1, 2, 3. There are 3 distinct integers (1, 2, 3).

 

Constraints:

  • 1 <= n <= 1015

Solutions

Solution 1: Digit DP

The problem essentially asks us to count the number of integers in the range $[1, n]$ that do not contain the digit 0. We can solve this problem using digit DP.

We design a function $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$, which represents the number of valid solutions when we are currently processing the $i$-th digit of the number. We use $\text{zero}$ to indicate whether a non-zero digit has appeared in the current number, $\text{lead}$ to indicate whether we are still processing leading zeros, and $\text{limit}$ to indicate whether the current number is constrained by the upper bound. The answer is $\text{dfs}(0, 0, 1, 1)$.

In the function $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$, if $i$ is greater than or equal to the length of the number, we can check $\text{zero}$ and $\text{lead}$. If $\text{zero}$ is false and $\text{lead}$ is false, it means the current number does not contain 0, so we return $1$; otherwise, we return $0$.

For $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$, we can enumerate the value of the current digit $d$, then recursively calculate $\text{dfs}(i+1, \text{nxt_zero}, \text{nxt_lead}, \text{nxt_limit})$, where $\text{nxt_zero}$ indicates whether a non-zero digit has appeared in the current number, $\text{nxt_lead}$ indicates whether we are still processing leading zeros, and $\text{nxt_limit}$ indicates whether the current number is constrained by the upper bound. If $\text{limit}$ is true, then $up$ is the upper bound of the current digit; otherwise, $up$ is $9$.

The time complexity is $O(\log_{10} n \times D)$ and the space complexity is $O(\log_{10} n)$, where $D$ represents the count of digits from 0 to 9.

  • class Solution {
        private char[] s;
        private Long[][][][] f;
    
        public long countDistinct(long n) {
            s = String.valueOf(n).toCharArray();
            f = new Long[s.length][2][2][2];
            return dfs(0, 0, 1, 1);
        }
    
        private long dfs(int i, int zero, int lead, int limit) {
            if (i == s.length) {
                return (zero == 0 && lead == 0) ? 1 : 0;
            }
    
            if (limit == 0 && f[i][zero][lead][limit] != null) {
                return f[i][zero][lead][limit];
            }
    
            int up = limit == 1 ? s[i] - '0' : 9;
            long ans = 0;
            for (int d = 0; d <= up; d++) {
                int nxtZero = zero == 1 || (d == 0 && lead == 0) ? 1 : 0;
                int nxtLead = (lead == 1 && d == 0) ? 1 : 0;
                int nxtLimit = (limit == 1 && d == up) ? 1 : 0;
                ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit);
            }
    
            if (limit == 0) {
                f[i][zero][lead][limit] = ans;
            }
            return ans;
        }
    }
    
    
  • class Solution {
    public:
        long long countDistinct(long long n) {
            string s = to_string(n);
            int m = s.size();
            static long long f[20][2][2][2];
            memset(f, -1, sizeof(f));
    
            auto dfs = [&](this auto&& dfs, int i, int zero, int lead, int limit) -> long long {
                if (i == m) {
                    return (zero == 0 && lead == 0) ? 1 : 0;
                }
                if (!limit && f[i][zero][lead][limit] != -1) {
                    return f[i][zero][lead][limit];
                }
    
                int up = limit ? (s[i] - '0') : 9;
                long long ans = 0;
                for (int d = 0; d <= up; d++) {
                    int nxtZero = zero || (d == 0 && !lead);
                    int nxtLead = lead && d == 0;
                    int nxtLimit = limit && d == up;
                    ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit);
                }
    
                if (!limit) f[i][zero][lead][limit] = ans;
                return ans;
            };
    
            return dfs(0, 0, 1, 1);
        }
    };
    
    
  • class Solution:
        def countDistinct(self, n: int) -> int:
            @cache
            def dfs(i: int, zero: bool, lead: bool, lim: bool) -> int:
                if i >= len(s):
                    return 1 if (not zero and not lead) else 0
                up = int(s[i]) if lim else 9
                ans = 0
                for j in range(up + 1):
                    nxt_zero = zero or (j == 0 and not lead)
                    nxt_lead = lead and j == 0
                    nxt_lim = lim and j == up
                    ans += dfs(i + 1, nxt_zero, nxt_lead, nxt_lim)
                return ans
    
            s = str(n)
            return dfs(0, False, True, True)
    
    
  • func countDistinct(n int64) int64 {
    	s := []byte(fmt.Sprint(n))
    	m := len(s)
    	var f [20][2][2][2]int64
    	for i := range f {
    		for j := range f[i] {
    			for k := range f[i][j] {
    				for t := range f[i][j][k] {
    					f[i][j][k][t] = -1
    				}
    			}
    		}
    	}
    
    	var dfs func(i, zero, lead, limit int) int64
    	dfs = func(i, zero, lead, limit int) int64 {
    		if i == m {
    			if zero == 0 && lead == 0 {
    				return 1
    			}
    			return 0
    		}
    
    		if limit == 0 && f[i][zero][lead][limit] != -1 {
    			return f[i][zero][lead][limit]
    		}
    
    		up := 9
    		if limit == 1 {
    			up = int(s[i] - '0')
    		}
    
    		var ans int64 = 0
    		for d := 0; d <= up; d++ {
    			nxtZero := zero
    			if d == 0 && lead == 0 {
    				nxtZero = 1
    			}
    			nxtLead := 0
    			if lead == 1 && d == 0 {
    				nxtLead = 1
    			}
    			nxtLimit := 0
    			if limit == 1 && d == up {
    				nxtLimit = 1
    			}
    			ans += dfs(i+1, nxtZero, nxtLead, nxtLimit)
    		}
    
    		if limit == 0 {
    			f[i][zero][lead][limit] = ans
    		}
    		return ans
    	}
    
    	return dfs(0, 0, 1, 1)
    }
    
    
  • function countDistinct(n: number): number {
        const s = n.toString();
        const m = s.length;
    
        const f: number[][][][] = Array.from({ length: m }, () =>
            Array.from({ length: 2 }, () => Array.from({ length: 2 }, () => Array(2).fill(-1))),
        );
    
        const dfs = (i: number, zero: number, lead: number, limit: number): number => {
            if (i === m) {
                return zero === 0 && lead === 0 ? 1 : 0;
            }
    
            if (limit === 0 && f[i][zero][lead][limit] !== -1) {
                return f[i][zero][lead][limit];
            }
    
            const up = limit === 1 ? parseInt(s[i]) : 9;
            let ans = 0;
            for (let d = 0; d <= up; d++) {
                const nxtZero = zero === 1 || (d === 0 && lead === 0) ? 1 : 0;
                const nxtLead = lead === 1 && d === 0 ? 1 : 0;
                const nxtLimit = limit === 1 && d === up ? 1 : 0;
                ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit);
            }
    
            if (limit === 0) {
                f[i][zero][lead][limit] = ans;
            }
            return ans;
        };
    
        return dfs(0, 0, 1, 1);
    }
    
    

All Problems

All Solutions