Solution using Digit DP by Top-down and Bottom-up
Code\n\n### Top-down approach\npython3 []\nclass Solution:\n    def convert(self, digit):\n        return ord(digit) - ord(\'0\')\n\n    # f1 bool: has smaller 
# Code\n\n### Top-down approach\n```python3 []\nclass Solution:\n    def convert(self, digit):\n        return ord(digit) - ord(\'0\')\n\n    # f1 bool: has smaller digit appeared?\n    # f2 int: bitmask for tracking appeared digits\n    # f3 bool: leading zeros?\n    def digitDP(self, i, f1, f2, f3, s, dp):\n        if i>=len(s):\n            return 1\n        if dp[i][f1][f2][f3] != None:\n            return dp[i][f1][f2][f3]\n        bound = 10\n        if not f1:\n            bound = self.convert(s[i]) + 1\n        cnt = 0\n        # digit 0 -> 9 at i\n        for digit in range(bound):\n            # if not leading zeros and current digit is 0 but exists in f2\n            if not f3 and digit==0 and f2&1 == 1:\n                continue\n\n            # if digit is chosen\n            if f2 & (1<<digit) != 0:\n                continue\n            \n            newF1 = f1 or (digit<self.convert(s[i]))\n            newF2 = f2\n\n            # if leading zeros and digit is 0, keep leading zeros\n            newF3 = f3 and digit==0\n            # if not leading zeros, add digit to appeared set (include 0)\n            if not newF3:\n                newF2 ^= (1<<digit)\n            \n            cnt += self.digitDP(i+1, newF1, newF2, newF3, s, dp)\n\n        dp[i][f1][f2][f3] = cnt\n\n        return dp[i][f1][f2][f3]\n\n    def topDown(self, n):\n        # because find numers with condition at least one tougher than condition no repeated digits\n        # therefore, I will find all the number without repeated digits and then get the required number by all number - no repeated\n        s = str(n)\n        l = len(s)\n        dp = [[ [ [ None for _ in range(2) ] for _ in range(1<<11) ] for _ in range(2) ] for _ in range(l)]\n        return n - self.digitDP(0, 0, 0, 1, s, dp) + 1 \n\n    def numDupDigitsAtMostN(self, n: int) -> int:\n        return self.topDown(n)\n```\n\n### Bottom-up approach\n```python3 []\nclass Solution:\n    def convert(self, digit):\n        return ord(digit) - ord(\'0\')\n\n    def bottomUp(self, n):\n        s = str(n)\n        l = len(s)\n\n        # dp[i][f1][f2][f3]\n        # the ith digit from left\n        # f1 bool: has smaller digit appeared?\n        # f2 int: bitmask for tracking appeared digits\n        # f3 bool: leading zeros?\n        dp = [[ [ [ 0 for _ in range(2) ] for _ in range(1<<11) ] for _ in range(2) ] for _ in range(l+1)]\n\n        # base case: all the zero length will be treated as successful\n        for f1 in range(2):\n            for f2 in range(1<<11):\n                for f3 in range(2):\n                    dp[l][f1][f2][f3] = 1\n\n        for i in range(l-1, -1, -1):\n            for f1 in range(2):\n                for f2 in range(1<<11):\n                    for f3 in range(2):\n                        bound = 10\n                        if f1==0:\n                            bound = self.convert(s[i]) + 1\n\n                        # digit 0 -> 9 at i\n                        for digit in range(bound):\n                            # if not leading zeros and current digit is 0 but exists in f2\n                            if f3==0 and digit==0 and f2&1 == 1:\n                                continue\n                            # if digit is chosen\n                            if f2 & (1<<digit) != 0:\n                                continue\n\n                            newF1 = f1==1 or (digit<self.convert(s[i]))\n                            newF2 = f2\n\n                            # if leading zeros and digit is 0, keep leading zeros\n                            newF3 = f3==1 and digit==0\n                            # if not leading zeros, add digit to appeared set (include 0)\n                            if not newF3:\n                                newF2 ^= (1<<digit)\n                            \n                            dp[i][f1][f2][f3] += dp[i+1][newF1][newF2][newF3]\n\n        return n - dp[0][0][0][1] + 1\n\n    def numDupDigitsAtMostN(self, n: int) -> int:\n        return self.bottomUp(n)\n```
['Dynamic Programming', 'Bitmask', 'Python3']