# 902. Numbers At Most N Given Digit Set

**<font color=red>难度: hard</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/numbers-at-most-n-given-digit-set/description/

> 内容描述

```
We have a sorted set of digits D, a non-empty subset of {'1','2','3','4','5','6','7','8','9'}.  (Note that '0' is not included.)

Now, we write numbers using these digits, using each digit as many times as we want.  For example, if D = {'1','3','5'}, we may write numbers such as '13', '551', '1351315'.

Return the number of positive integers that can be written (using the digits of D) that are less than or equal to N.

 

Example 1:

Input: D = ["1","3","5","7"], N = 100
Output: 20
Explanation: 
The 20 numbers that can be written are:
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.
Example 2:

Input: D = ["1","4","9"], N = 1000000000
Output: 29523
Explanation: 
We can write 3 one digit numbers, 9 two digit numbers, 27 three digit numbers,
81 four digit numbers, 243 five digit numbers, 729 six digit numbers,
2187 seven digit numbers, 6561 eight digit numbers, and 19683 nine digit numbers.
In total, this is 29523 integers that can be written using the digits of D.
 

Note:

D is a subset of digits '1'-'9' in sorted order.
1 <= N <= 10^9
```

## 解题方案

> 思路 1
******- 时间复杂度: O(lgN)******- 空间复杂度: O(N)******


这里时间复杂度为 O(lgN) 是因为我们把N看作是input里面N的大小

并且pow(x, y)的时间复杂度为:

1. For y < 2^63, there's a loop of size ceil(log_2(y)), 
2. but for larger y, the result is calculated using Exp(y * Log(x)).


参见[lee215](https://leetcode.com/problems/numbers-at-most-n-given-digit-set/discuss/168279/Python-O(logN))
```
- N has n digits, so all numbers less than n digits are valid, which are: sum(len(D) ** i for i in range(1, n))
- The loop is to deal with all numbers with n digits, considering from N[0], N[1] back to N[n-1]. 
For example, N[0] is valid only for c in D if c <= N[0]. 
If c < N[0], then N[1], ..., N[n-1] can take any number in D but if c == N[0], then we need consider N[1], 
and the iteration repeats. That's why if N[i] not in D, then we don't need to repeat the loop anymore.
- Finally i==n is addressed at the end when there exists all c in D that matches N
```

```python
class Solution(object):
    def atMostNGivenDigitSet(self, D, N):
        """
        :type D: List[str]
        :type N: int
        :rtype: int
        """
        N = str(N)
        n = len(N)
        res = sum(pow(len(D), i) for i in range(1, n)) # 考虑少于n位的答案
        i = 0
        while i < n: # 开始考虑刚好为n位的答案
            res += sum(c < N[i] for c in D) * pow(len(D), n-i-1) # 每次只考虑比N当前位置的数字小的数字
            if N[i] not in D: # 如果N当前位置的数字都不在D里面了，我们考虑不了下一个位置
                break
            i += 1
        return res + (i==n) # 如果N判断到最后一个位置的数字了，这个数字都还在D里面，我们就知道有一个刚好等于N的组合
```
