Java easy to understand(Digit Dp + Bit Manipulation)
\nclass Solution {\n    Integer[][][][] dp;\n    private int solve(char[] num, int curDig, boolean isStrict, int bit, boolean repeated) {\n        if(curDig == 
```\nclass Solution {\n    Integer[][][][] dp;\n    private int solve(char[] num, int curDig, boolean isStrict, int bit, boolean repeated) {\n        if(curDig == num.length) return repeated ? 1 : 0;\n        if(dp[curDig][isStrict ? 1 : 0][bit][repeated ? 1 : 0] != null) return dp[curDig][isStrict ? 1 : 0][bit][repeated ? 1 : 0];\n        int end = isStrict ? num[curDig] - \'0\' : 9;\n        int res = 0;\n        for(int i = 0; i <= end; i++) {\n            if(bit == 0 && i == 0) \n                res += solve(num, curDig + 1, isStrict && i == end, bit, repeated);\n            else\n                res += solve(num, curDig + 1, isStrict && i == end, bit | (1 << i), repeated | (bit & (1 << i)) != 0);\n        }\n        return dp[curDig][isStrict ? 1 : 0][bit][repeated ? 1 : 0] = res;\n    }\n    public int numDupDigitsAtMostN(int n) {\n        char[] num = String.valueOf(n).toCharArray();\n        dp = new Integer[10][2][1025][2];\n        return solve(num, 0, true, 0, false);\n    }\n}\n```
['Dynamic Programming', 'Bit Manipulation', 'Recursion', 'Bitmask', 'Java']