题目描述:
Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.
题目大意:
给定一个整数n,计算所有小于等于n的非负整数中数字1出现的次数。
例如:
给定 n = 13,
返回6, 因为数字1在下面的数字中出现:1, 10, 11, 12, 13(共6次)。
解题思路:
注意题目要求为统计1出现的次数,而非包含1的数字出现的次数(一开始理解题意时出现了偏差)
在此列出两种解法:
解法I:预处理+从高位向低位枚举1的出现次数
预处理数组ones,ones[x]表示[0, 10 ^ x)范围内包含的1的个数 由高位向低位依次遍历数字n的每一位digit 记digit右边(低位)数字片段为n,size为当前位数,cnt为1的总数 若digit > 1,则cnt += digit * ones[size - 1] + 10 ^ (size - 1) 若digit = 1,则cnt += n + ones[size - 1] + 1
Python代码:
class Solution:
# @param {integer} n
# @return {integer}
def countDigitOne(self, n):
if n < 0:
return 0
ones, x = [0], 0
while 10 ** x <= 0x7FFFFFFF:
ones.append(ones[x] * 10 + 10 ** x)
x += 1
cnt, size = 0, len(str(n))
for digit in str(n):
digit = int(digit)
size -= 1
n -= digit * 10 ** size
if digit > 1:
cnt += digit * ones[size] + 10 ** size
elif digit == 1:
cnt += n + ones[size] + 1
return cnt
解法II:计数原理,按位统计该位为1时可能包含的数字总数
参考:https://leetcode.com/discuss/44314/accepted-c-solution-with-explanation
由低位向高位依次遍历数字n的每一位curn 记当前位数为c,curn左边(高位)的数字片段为highn,cur右边(低位)的数字片段为lown,lowc = 10 ^ c 若curn = 0,则高位范围为0 ~ highn - 1,低位0 ~ lowc - 1 若curn = 1,则高位范围为0 ~ highn - 1,低位0 ~ lowc - 1;或者 高位为highn, 低位0 ~ lown 若curn > 1,则高位范围为0 ~ highn, 低位为0 ~ lowc - 1
C++代码:
int countDigitOne(int n) {
long long int res(0);
int highn(n), lowc(1), lown(0);
while(highn > 0){
int curn = highn % 10;
highn = highn / 10;
if (1 == curn) {
//higher: 0~(highn-1); lower: 0 ~ (lowc-1)
res += highn * lowc;
//higher: highn ~ highn; lower:0~lown
res += lown + 1;
} else if (0 == curn) {
//curn < 1
//higher: 0~(highn-1); lower: 0 ~ (lowc-1)
res += highn * lowc;
} else {
//curn > 1
res += (highn + 1) * lowc;
}
//update lown and lowc
lown = curn * lowc + lown;
lowc = lowc * 10;
}
return res;
}
下面的代码思路同前所述,更加精简
摘自:https://leetcode.com/discuss/44281/4-lines-o-log-n-c-java-python
Python代码:
def countDigitOne(self, n):
ones, m = 0, 1
while m <= n:
ones += (n/m + 8) / 10 * m + (n/m % 10 == 1) * (n%m + 1)
m *= 10
return ones
本文链接:http://bookshadow.com/weblog/2015/07/08/leetcode-number-digit-one/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。