【题目来源】
233. Number of Digit One(AC代码)
【分析】
以 5 5 位数为例,其中 X X 可取, len=5 len = 5 为该数字的长度
首先考虑最高位(万位)上 1 1 出现的次数
若,则从 10000–17429 10000 – 17429 ,共 7430 7430 次,这个次数可以通过除去 X X 之后的数字加 1 1 得到
若,则从 10000–19999 10000 – 19999 ,共 10len=10000 10 len = 10000 次
if( first == 1 ) result += stoi( str.substr( 1, len - 1 ) ) + 1; else if( first > 1 ) result += (int)( pow( 10, len - 1 ) );
然后考虑出现在非最高位上 1 1 出现的次数
以为例, 37429 37429
划分为 4 4 个区间,, 7430–17429 7430 – 17429 , 17430–27429 17430 – 27429 , 27430–37429 27430 – 37429
第 1 1 个区间长度为,剩余区间长度均为 10000 10000对于第 1 1 个区间,出现的次数可以通过递归调用得到
result += helper( str.substr( 1, len - 1 ) );
对于第 2 2 个区间,共包含 10000 10000 个数,除去万位,构成了从 0000 0000 到 9999 9999 的完整循环
于是统计从 0000 0000 到 9999 9999 这个序列中 1 1 出现的次数:可以出现在 4 4 个位置(千位、百位、十位、个位),每个位置共出现了次(剩下 3 3 个位置,每个位置都可以取,即 10×10×10 10 × 10 × 10 )
统计结果:从 0000 0000 到 9999 9999 的序列中 1 1 出现的次数为更一般化的表达式为 (len−1)×10len−2 ( len − 1 ) × 10 len − 2 ,这个式子对于剩下2个区间仍然成立
于是 X=3 X = 3 时,共有 3 3 个区间,非最高位的出现的次数为 X×(len−1)×10len−2 X × ( len − 1 ) × 10 len − 2
result += first * (len - 1) * (int)( pow( 10, len - 2 ) );
【AC代码】
class Solution { public: int countDigitOne(int n) { // 测试样例有负数,答案为0 if( n < 0 ) return 0; return helper( to_string(n) ); } int helper( string str ) { int len = str.length(); int first = str[0] - '0'; // first为数字的最高位 // 递归终止条件 if( len == 1 ) return first == 0 ? 0 : 1; int result = 0; // 最高位 if( first == 1 ) result += stoi( str.substr( 1, len - 1 ) ) + 1; else if( first > 1 ) result += (int)( pow( 10, len - 1 ) ); // 非最高位 result += helper( str.substr( 1, len - 1 ) ); result += first * (len - 1) * (int)( pow( 10, len - 2 ) ); return result; } };