This commit is contained in:
ShusenTang 2020-02-10 15:34:42 +08:00
parent 0f3807f599
commit 5bc9df0008
2 changed files with 85 additions and 0 deletions

View File

@ -172,6 +172,7 @@ My LeetCode solutions with Chinese explanation. 我的LeetCode中文题解。
| 230 |[Kth Smallest Element in a BST](https://leetcode.com/problems/kth-smallest-element-in-a-bst/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/230.%20Kth%20Smallest%20Element%20in%20a%20BST.md)|Medium| | | 230 |[Kth Smallest Element in a BST](https://leetcode.com/problems/kth-smallest-element-in-a-bst/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/230.%20Kth%20Smallest%20Element%20in%20a%20BST.md)|Medium| |
| 231 |[Power of Two](https://leetcode.com/problems/power-of-two)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/231.%20Power%20of%20Two.md)|Easy| | | 231 |[Power of Two](https://leetcode.com/problems/power-of-two)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/231.%20Power%20of%20Two.md)|Easy| |
| 232 |[Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/232.%20Implement%20Queue%20using%20Stacks.md)|Easy| | | 232 |[Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/232.%20Implement%20Queue%20using%20Stacks.md)|Easy| |
| 233 |[Number of Digit One](https://leetcode.com/problems/number-of-digit-one/)|[C++](solutions/233.%20Number%20of%20Digit%20One.md)|Hard| |
| 234 |[Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/234.%20Palindrome%20Linked%20List.md)|Easy| | | 234 |[Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/234.%20Palindrome%20Linked%20List.md)|Easy| |
| 235 |[Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/235.%20Lowest%20Common%20Ancestor%20of%20a%20Binary%20Search%20Tree.md)|Easy| | | 235 |[Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/235.%20Lowest%20Common%20Ancestor%20of%20a%20Binary%20Search%20Tree.md)|Easy| |
| 236 |[Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/236.%20Lowest%20Common%20Ancestor%20of%20a%20Binary%20Tree.md)|Medium| | | 236 |[Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/236.%20Lowest%20Common%20Ancestor%20of%20a%20Binary%20Tree.md)|Medium| |

View File

@ -0,0 +1,84 @@
# [233. Number of Digit One](https://leetcode.com/problems/number-of-digit-one/)
# 思路
给定整数n求1~n这n个数中数字1出现的个数例如 n = 2345的结果可以根据 n = 345 和 n = 999 来求得。
## 思路一
比较好想的是递归法,核心思想就是每次去掉最高位。
* 递归出口:当`n < 1`时直接返回0
* 否则我们假设n表示成"aB"的形式其中a代表n的最高位B代表其余位例如若 n = 2345 则a=2B=345。我们还令M为与n位数相同的最小的数即若 n=2345 则 M = 1000。所以很明显我们有等式`n = a * M + B`。
* 先考虑出现在最高位的1的个数。所以这里需要考虑a是否为1若是则有B+1个否则有M个例如若n = 1234那么千位的1就有235个即1000~1234若n = 2234则有1000个即1000~1999
* 再考虑非最高位的1的个数。0到`a*M`中出现在非最高位的1的个数为`a*countDigitOne(M-1)`例如0~3000中出现在非最高位即个十百位的1的个数为`3*countDigitOne(999)``a*M+1`到`a*M+B`中出现在非最高位的1的个数为`a*countDigitOne(B)`例如3001到3421中出现在非最高位即个十百位的1的个数为`countDigitOne(421)`。
* 综上总的1的个数为`a * countDigitOne(M - 1) + countDigitOne(B) + (a == 1 ? B + 1 : M)`。
每次递归都去掉了最高位所以递归次数和位数相同即时间复杂度为O(logn)空间复杂度O(logn)。
## 思路二
再来看看迭代的思路。
核心思想就是统计出每位(个十百千...上1出现的个数累加起来就是1出现的总个数。
例如现在统计百位上1出现的次数。
* 先将n根据百位分成两部分`n = 100*a + b`。
* 此时a的个位的值有三种情况
* a的个位大于1。例如 n = 31456则 a = 314a的个位是4。此时1-n的百位是1的次数为`32*100`即形为A1BA为0-31B为0-99
* a的个位等于1。即n的百位是1例如 n = 31156则 a = 311。此时0-n的百位是1的次数为`31*100 + 56 + 1`即形为A1BA为0-30B为0-99或者311CC为0到56
* a的个位等于0。即n的百位是1例如 n = 31056则 a = 310。此时0-n的百位是1的次数为`31*100`即形为A1BA为0-30B为0-99
|n的百位| 0到n的百位是1的次数 | n举例 | a | b | 0到n的百位是1的次数 |
|--- | --- | --- | --- | --- | --- |
| 大于1 | `(a/10 + 1) * 100` | 31456 | 314 | 56 | `32*100` |
| 等于1 | `(a/10) * 100 + b + 1` | 31156 | 311 | 56 | `31*100 + 56 + 1` |
| 等于0 | `(a/10) * 100` | 31056 | 310 | 56 | `31*100` |
上述三个情况可以用一个表达式写出:
```
(a+8)/10 * 100 + (a % 10 == 1) * (b + 1)
```
有了上述分析,我们就可以写出代码了,注意避免溢出。
时间复杂度为O(logn)空间复杂度O(1)。
# C++
## 思路一
``` C++
class Solution {
public:
int countDigitOne(int n) {
if(n < 1) return 0;
// else if(n < 10) return 1;
// n = 2345 -> a=2, M=1000, B=345
int a = n, M = 1, B = 0;
while(a >= 10){
a /= 10;
M *= 10;
}
B = n % M;
int res = a * countDigitOne(M - 1) + countDigitOne(B); //非最高位的1的个数
res += (a == 1 ? B + 1 : M); //最高位的1的个数
return res;
}
};
```
## 思路二
``` C++
class Solution {
public:
int countDigitOne(int n) {
int ones = 0;
for (long long m = 1; m <= n; m *= 10) {
int a = n / m, b = n % m;
ones += (a + 8) / 10 * m + (a % 10 == 1) * (b + 1);
}
return ones;
}
};
```