问题: 输入一个整数n,求从1 到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1的数字有1,10,11和12,1一共出现了5次。
这是《剑指offer 名企面试官精讲典型编程题》一书中的第32题。书中Herry给出了递归算法。我自己写的是循环算法。虽然有着不同写法,但大体上思路是一致的。我的算法并不比Herry的强。写下来只是提供另外的一个解法。
分析:要得到一个整数中出现的1的次数,其实就是算出1在个位,十位,百位等等中出现的次数总和。在个位上,1在0至9中出现的频率只是1次,其它023456789都和1无关。但是整个个位的循环次数是除去个位的整数值加1(或不加)。如,23, 个位的1出现的次数是3 (23去掉3再加1),即01,11,21;123个位的1出现次数是13(123去掉3加1),即01,11,21,31,41,51,61,71,81,91,101,111,121;以此类推。
再来看十位, 1在0至9中出现的频率也只是1次,但是和个位不同的是,十位中的1却要因为个位的原因至多循环10次(或不到10次),如10,11,12,13,14,15,16,17,18,19,所以整个十位的循环次数是除去个位和十位的整数值乘以10(或不乘)。
百位是也是如此,百位上的1要为十位和个位循环至多10*10次。
由此,我们就可以得出了算法。
时间复杂性是O(n)
private int GetOneOccurence( int piNum ) {
String lsNum = piNum.ToString();
int liResult = 0;
// calculate result from first digit to last one
for ( int i = lsNum.Length - 1; i >= 0; i-- ) {
liResult += GetOneOccurence( lsNum, i );
}
return liResult;
}
private int GetOneOccurence( String psNum, int piLoopPosition ) {
String lsSuffix;
int liResult = 0;
// current: digit in current position that is specified by piPos
// Suffix: get following digits from current digit
// Prefix: get digits before current digit
// e.g. 456791, current number is 6, the lsSuffix is 791, prefix is 45.
lsSuffix = psNum.Substring( piLoopPosition + 1 );
int liCurNum = int.Parse( psNum.Substring( piLoopPosition, 1 ) ) ;
int liPrefix = ( piLoopPosition == 0 ? 0 : int.Parse( psNum.Substring( 0, piLoopPosition ) ) );
int liSuffix = ( String.IsNullOrEmpty( lsSuffix ) ? 0 : int.Parse( lsSuffix ) );
// Get power suffix of current number
// e.g: 1,234 , power of suffix is 100 when current number is 2
int liSufPow = (int)Math.Pow( 10, lsSuffix.Length );
// if current number is great than 1, then 1 occurence in this position is ( prefix + 1 ) * power of suffix
// e.g: 12345, the current number is 3 now. then 1 occurence in third position is ( 12 + 1 ) * 100
// that is: 01100 to 12100, plus 100 to 199
// if current number is equal to 1, then occurence is prefix * power of suffice + suffix + 1
// e.g: 21345, current number is 1. the value is 2 * 1000 + 345 + 1
// that is: 1000 to 1345, plus 11000 to 21000
// the last situation is that current number is equal to 0. So, occurence is simple to prefix * power of suffix
// e.g: 12045. the result should be 12 * 100
// that is 00100 - 00199, 01100 - 01199, 02100 - 02199,... ,11100 - 11199.
if ( liCurNum > 1 ) {
liResult = ( liPrefix + 1 ) * liSufPow;
} else if ( liCurNum == 1 ) {
liResult = liPrefix * liSufPow + ( liSuffix + 1 );
} else {
liResult = liPrefix * liSufPow;
}
return liResult;
}原文:http://blog.csdn.net/liberwang/article/details/19026361