题目大致意思是要求出1~N
中数出现的1的个数。有种很直接的办法就是枚举1~N
中的数,统计每个数共有多少位出现1,最后把结果累加起来。但这种办法在数据量大时用时过长,我们可以换个角度思考,把会被记录到总数的1按照位进行划分,统计第i
位为1
的在1~N
中数字的个数,把得到的结果累加起来,就能得到1~N
中数出现的1的个数。
举例
令N = 30710
,从第一位开始统计每一位为1时数字的个数。
- 第一位为1时
为了不超过N
,第一位的前面四位可以取0000,0001,...,3070
,如果取3071
就会得到30711
超过30710
。 - 第二位为1时
此时第二位前的三个数可以取000,001,...,306
,最后一位可以取任意的0~9
中的数。
当前三位取307
时,最后一位就只能取0
了 - 第三位取1时
此时前两位可以取00,01,...,30
,而后两位可以取00,01,...,99
以此类推
规律
设我们要讨论的数是N
,讨论N
的一位(用a
表示,讨论下一位时就让a
乘以10
),该位为now
,N
在now
左侧的部分大小为left
,右侧部分为right
,该位为1的数字个数为ans,满足等式:
- 若
now = 0
,ans = left * a
- 若
now = 1
,ans = left * a + right + 1
- 若
now > 1
,ans = (left + 1) * a
实现
只要维护一个迭代过程中不断乘以10表示进一位的数a
,left,now,right
都可以通过除法和求余得到。