1012._Numbers_With_1_Repeated_Digit.md 3.0 KB
Newer Older
1
# 1012. Numbers With 1 Repeated Digit
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

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

## 刷题内容

> 原题连接

* https://leetcode.com/problems/numbers-with-1-repeated-digit/

> 内容描述

```
Given a positive integer N, return the number of positive integers less than or equal to N that have at least 1 repeated digit.

 

Example 1:

Input: 20
Output: 1
Explanation: The only positive number (<= 20) with at least 1 repeated digit is 11.
Example 2:

Input: 100
Output: 10
Explanation: The positive numbers (<= 100) with atleast 1 repeated digit are 11, 22, 33, 44, 55, 66, 77, 88, 99, and 100.
Example 3:

Input: 1000
Output: 262
 

Note:

1 <= N <= 10^9
```

## 解题方案

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

44

45 46
算有重复的,我们可以先算出没有重复的,然后返回`(总数-没有重复)`即可

47 48
比赛中我想到了可以这样做,但是实现的时候TLE了,赛后看了[[Java/Python] Count the Number Without Repeated Digit](https://leetcode.com/problems/numbers-with-1-repeated-digit/discuss/256725/JavaPython-Count-the-Number-Without-Repeated-Digit)

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
那么没有重复怎么算呢?

对于一个N位digit的数字,小于等于它的没有重复的有以下两种:
1. digit数小于N的,对于这部分,直接算即可
2. digit数小于N的,对于这部分,我们必须要让构造出的数字小于等于N


```python
class Solution:
    def numDupDigitsAtMostN(self, N):
        L = list(map(int, str(N + 1)))
        res, n = 0, len(L)

        def A(m, n):
            return 1 if n == 0 else A(m, n - 1) * (m - n + 1)

        for i in range(1, n): 
            res += 9 * A(9, i - 1)
        s = set()
        for i, x in enumerate(L):
            for y in range(0 if i else 1, x):
                if y not in s:
                    res += A(9 - i, n - i - 1)
            if x in s: 
                break
            s.add(x)
        return N - res
```

For anyone who doesn't understand the function `def A()`, you can see the iterative version of it below.
```python
        def A(m, n):
            res = 1
            for i in range(n):
                res *= m
                m -= 1
            return res
```
It means the `permutation` of `m * (m-1) * ... * (m-(n-1))`.

And for why use `9*A(9,i-1)` instead of `A(9,i)`, that's because there should be no leading `0`, but the following digit can be `0`.
90

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

***将函数A重命名为permu***

```python
class Solution:
    def numDupDigitsAtMostN(self, N):
        L = list(map(int, str(N + 1)))
        res, n = 0, len(L)

        def permu(m, n):
            res = 1
            for i in range(n):
                res *= m
                m -= 1
            return res

        for i in range(1, n): 
            res += 9 * permu(9, i - 1)
            
        s = set()
        for i, x in enumerate(L):
            for y in range(0 if i else 1, x):
                if y not in s:
                    res += permu(9 - i, n - i - 1)
            if x in s: 
                break
            s.add(x)
        return N - res
```